利用.NET的Reflection增强对象工厂的扩展性

C#单例模式进阶:基于泛型与反射的通用基类设计与自动初始化 单例模式是软件设计中确保类仅有一个实例并提供全局访问点的经典创建型模式,其核心原理在于控制实例化过程并维护静态引用。在C#等现代语言中,该模式的技术价值体现在管理全局状态、共享资源(如配置、连接池)及服务定位,广泛应用于桌面应用、服务后台及游戏开发等场景。传统实现常面临代码重复与初始化管理难题,而结合泛型约束与反射机制,可构建通用基类实现自动发现与懒加载。本文聚焦于利用Lazy<T>保障线程安全,并通过程序集扫描实现零配置依赖管理,为构建轻量级IoC容器提供实践参考。 阅读详情

对象工厂

 

对象工厂(Object Factory)模式通常被用来从一个派生系统中产生某个对象,并将其作为基类的实例返回,从而获得基类的接口,并尽量掩盖派生类的细节,以便充分利用面向对象的多态性来获得强大的功能。通常,对象工厂的实现方法是,在一个工厂方法中,先利用一个基于类型标记(type tag)的switch语句找出适当的类型,然后创建该类型的实例并返回之。

 

举例来说,设想一个图形系统,它包括了线、圆、矩形等元素,这些元素具有一些公共的操作,比如Draw、Resize等。那么我们可能具有下面这样一个继承体系:

 

 

为了能够在对象工厂中区分这些类,我们还需要为它们分别指定一个类型标记。这些类型标记可以是Enumeration、整数、字符串等能够唯一地标记这些类的值。用它们的类名字符串作为标记看起来不错。我们可以使用下面这个对象工厂来创建Shape对象:

 

    public sealed class ShapeFactory

    {

        private ShapeFactory()

        {

        }

 

        public static BaseShape CreateShape(string shapeID)

        {

            switch(shapeID)

            {

                case "Rectangle":

                    return new Rectangle();

                case "Circle":

                    return new Circle();

                case "Line":

                    return new Line();

                default:

                    return null;

            }

        }

    }

 

ShapeFacory的唯一用途就是用来创建Shape实例,我们不希望它本身那能够被继承,或者能够被实例化,因此,它被声明为sealed,并具有一个私有构造函数。当我们需要得到某个Shape的实例时,只要调用ShapeFactory的CreateShape()方法,并传入一个适当的shapeID字符串,CreateShape()就会为我们返回正确的Shape实例了。

 

增强扩展性

 

现在我们拥有了一个Shape工厂,它工作的不错。但是这个工厂具有一个明显的不足:难以扩充。每当系统中新增加一个Shape类时,我们都不得不修改CreateShape()方法,向其中加入新的case语句。这在我们的产品没发布之前还好,我们可以完全控制我们的代码。但当我们的产品发布之后,用户可以很容易地从BaseShape派生自己的Shape类,但他们却很难利用CreateShape()方法将他们的Shape类加入到系统中,因为他们无法修改CreateShape()方法的实现。因此这个Shape工厂还需要一些扩展性。但是解决这个问题的一个主要的障碍是,如果不使用switch语句,那么CreateShape()将无法预先知道到底存在哪些Shape类,以及类型标记与具体的类之间的关系。

 

Alexandrescu在他的《Modern C++ Design》中针对这个问题给出了一个C++解法。他在对象工厂类中利用一个std::map来维护类型标记与类型的创建方法之间的关系,并在对象工厂类中增加了两个接口Register()和Unregister(),用来在此map中注册或注销类型标记和类型创建方法。每增加一个Shape类时,需要同时为这个类写一个匿名名字空间,在此空间中调用Register()方法,将自己的类型标记和创建方法注册到对象工厂中。

 

在C#中,我们可以借鉴Alexandrescu的方法,在对象工厂中利用一个Hashtable来维护类型标记与类型之间的关系,利用Register()方法来注册。每个Shape类必须负责自己的注册工作,因此我们为每个Shape类增加一个RegisterShape()方法,它调用ShapeFactory.Register()来注册自己。但是有两个问题:

 

1、   对RegisterShape()方法的调用应当何时进行呢?

2、   C#并不支持匿名名字空间,那么如何来调用每个Shape类的RegisterShape()方法呢?

 

对于第一个问题,我们有一个时机,那就是在CreateShape()方法被调用之前,各个Shape类必须已经完成了注册。在静态构造函数中完成对RegisterShape()的调用到是个不错的选择。

 

对于第二个问题,我们可以使用Reflection机制,首先遍历所有的类型,找出由BaseShape派生的类型,然后分别调用它们的RegisterShape()方法。

 

按照以上思路,ShapeFactory的实现代码如下:

    public sealed class ShapeFactory

    {

        private static Hashtable _creationMap = null;

 

        static ShapeFactory()

        {

            _creationMap = new Hashtable();

 

            Assembly a = typeof(ShapeFactory).Module.Assembly;

            Module[] modules = a.GetModules();

            for(int i = 0; i < modules.Length; i++)

            {

                Type[] types = modules[i].GetTypes();

                for(int j = 0; j < types.Length; j++)

                {

                    if(!types[j].Equals(typeof(BaseShape))

                        && types[j].BaseType != null

                        && types[j].BaseType.Equals(typeof(BaseShape)))

                    {

                        Object obj = types[j].InvokeMember(null,

                            BindingFlags.DeclaredOnly |

                            BindingFlags.Public |

                            BindingFlags.Instance |

                            BindingFlags.CreateInstance,

                            null, null, null);

 

                        types[j].InvokeMember("RegisterShape",

                            BindingFlags.DeclaredOnly |

                            BindingFlags.Public | BindingFlags.NonPublic |

                            BindingFlags.Instance | BindingFlags.InvokeMethod,

                            null, obj, null);

                    }

                }

            }

        }

 

        public static void Register(string shapeID, Type shape)

        {

            if(!_creationMap.ContainsKey(shapeID))

                _creationMap.Add(shapeID, shape);

        }

 

        public static BaseShape CreateShape(string shapeID)

        {

            Type shape = (Type)_creationMap[shapeID];

 

            if(shape == null)

                return null;

 

            return (BaseShape)shape.InvokeMember(null,

                BindingFlags.DeclaredOnly |

                BindingFlags.Public |

                BindingFlags.Instance | BindingFlags.CreateInstance,

                null, null, null);

        }

    }

 

在CreateShape()方法第一次被调用之前,静态构造函数会先执行。它利用Reflection机制遍历所有的类型,对于由BaseShape派生的类型,先创建一个实例,然后调用其RegiserShape()方法,将其在Hashtable中注册。当CreateShape()方法被调用时,根据传入的shapeID从Hashtable中取出相应的类型,并返回其实例。这样,我们就有了一个具有一定扩展性的Shape工厂。

 

总结

 

在对象工厂中增加Reflection机制,可以在一定程度上增强对象工厂的扩展性。改进后的ShapeFactory不用再在每次增加了Shape类之后进行修改了,只要新加入的Shape类实现了RegiserShape()方法,它就能够被注册到对象工厂中,并被正确地创建。这样,我们甚至可以方便地为我们的系统实现插件功能。比如,我们可以指定一个插件目录,遍历这个目录,将其中的Shape类注册到工厂中。用户只需将他们的插件拷贝到这个目录下即可。

 

当然,Reflection也许并不是此问题的最佳解决方案。它需要遍历系统中所有的类型,执行效率不够高。还好静态构造函数只会被执行一次。希望本文能够起到抛砖引玉的作用。如果您有更好的方案,欢迎和我交流。我的联系方式:sam1111@citiz.net

 

Unity进阶:C#内存管理、设计模式与性能优化实战指南 在游戏开发中,内存管理与性能优化是保障应用流畅运行的核心技术。其原理在于理解编程语言的内存分配机制,例如C#的自动垃圾回收(GC)机制,不当的堆内存分配会触发GC导致卡顿。掌握值类型与引用类型的区别、避免装箱操作、合理使用对象池等技术,能显著提升程序效率,这对于资源受限的移动端和大型项目尤为重要。设计模式如观察者模式和状态模式,则为构建清晰、可维护的代码架构提供了模板,通过事件驱动和解耦组件来支撑复杂游戏逻辑。这些基础概念与工程实践的结合,最终服务于Unity开发场景,帮助开发者解决从对象销毁内存残留到代码 阅读详情

相关推荐

C#特性滥用风险与工程化精简实践

编程语言的抽象能力是双刃剑——它提升开发效率,也隐匿运行时复杂性。当C#引入dynamic、LINQ、Source Generator等高级特性时,其背后涉及的表达式树编译、状态机生成、编译期代码膨胀等机制,正悄然抬高调试成本与认知门槛。这类抽象泄漏现象,在金融、IoT、医疗等强稳定性场景中尤为致命:编译耗时飙升、GC暂停不可控、新人上手周期延长。本文基于真实项目数据,剖析C# 9~12关键特性的工程熵增表现,并提出以编译期守门(Roslyn Analyzer)、运行时监控(DiagnosticSource

didi9310的博客 390

我的实用设计模式 - Simple Factory和Reflection

更新1:使用as转换数据类型。 在上篇文章 我的实用设计模式 - Simple Factory,Factory Method和Abstract Factory 讲述了Simple Factory,Factory Method和Abstract Factory的关系以及演变过程。在这篇文章中,引入Reflection来实现Simple Factory,增强系统的可扩展性。 下面是Refle...

weixin_30387663的博客 169

MuleSoft企业级AI编排:让大模型真正融入ERP/CRM核心系统

AI编排(AI Orchestration)是将大语言模型与企业现有IT系统深度协同的关键范式,其本质不是简单调用LLM API,而是通过结构化契约、语义翻译与流程治理,解决LLM泛化能力与企业系统刚性元数据之间的根本矛盾。MuleSoft Anypoint Platform凭借开箱即用的SAP/Salesforce连接器、DataWeave精准数据转换、Runtime Fabric故障隔离及Anypoint Monitoring可观测性,天然支撑企业级大模型集成(Enterprise LLM Integr

358

均值回归策略实战指南:配对交易、协整分析与VECM模型详解及Python实现(awesome-quant-ai)

均值回归策略(Mean Reversion)是量化交易中最经典的策略类型之一:当价格偏离长期均衡后,"低买高卖"价差、等待回归获利。本文带你完整走一遍均值回归的实战路线——**配对交易、协整分析、VECM 模型**及对应的 **Python 实现**,所有学习资料与可运行代码均来自开源项目 **awesome-quant-ai**。 📌 **本文路线**:均值回归原理 → 配对交易三步法 →

gitblog_00813的博客 333

BepInEx框架深度解析:Unity游戏插件开发从入门到实战

在Unity游戏生态中,插件开发是扩展游戏功能、实现模组化的重要技术路径。其核心原理在于通过代码注入与运行时补丁技术,在不修改游戏原始文件的前提下,动态加载和执行自定义逻辑。这种非侵入式设计为游戏模组开发提供了稳定、安全的基础,极大地提升了开发效率与模组兼容性。BepInEx作为当前Unity游戏模组开发的事实标准框架,集成了Harmony补丁库、插件生命周期管理、配置文件系统等关键组件,形成了一个完整的工具链。它广泛应用于《星露谷物语》、《腐蚀》等热门游戏的模组开发,支持开发者快速构建功能增强、界面美化等

weixin_30947043的博客 285

c# .net 反射Reflection--初识篇,实现可配置,可扩展

引子 【C# 高级语言 (人类语言)】--->【编译器 编译】--->【DLL/EXE】里面有2个文件分别是【metadata】和【IL】--->【IL】--->【CLR/JIT】--->【机器码 (01010101)】 我们所写的语言是【C# 高级语言 (人类语言)】这里的c#也可以是PHP或者JAVA等高级语言,是人类可以看懂的。 然后,通过编译器,...

橙-极纪元-JJYCheng 671

Java深入解析篇二十八之动态代理

代理模式(Proxy Pattern) 是一种结构型设计模式,它为某个对象提供一个代理对象,由代理对象控制对原对象的访问。代理对象在客户端和目标对象之间起到中介作用,可以在不修改目标对象的前提下,增强目标对象的功能。代理模式的核心思想:在不改变原始类代码的情况下,通过引入代理类来给原始类附加功能。 1.2 代理模式的角色 角色 说明 Subject(抽象主题) 声明真实主题与代理的公共接口 RealSubject(真实主题) 被代理的真实对象 Proxy(代理) 持有真实主题的引用,

萧瑟余晖的博客 486

Java反射机制、代理模式和装饰器模式、IOC

1.反射机制 2.挥手握手

の博客 277

51c大模型~合集111

OpenAI 的某发言人表示:「为了提高清晰度和安全性,我们增加了一个额外的后处理步骤,其中模型会审查原始的思维链,删除任何不安全的内容,然后简化某些复杂的思维。可以看到,虽然 ChatGPT 确实完成了任务并展示了总结版的思维链,但似乎并未如 OpenAI 发言人说的那样给出与提示词语言同样语言的总结版。北大-灵初联合实验室表示,Align-DS-V的多模态强推理能力是VLA模型大脑端的核心,接下来的研究训练计划,是利用多模态推理模型的跨模态穿透能力,实现action穿透,最终实现真正高效的VLA模型。

whaosoft~aiotの开发板商城 2316

【信息科学与工程学】【通信工程】计算机科学与自动化——第二百三十三篇 云NaaS服务 系列二01

国家骨干网(含核心网、IP骨干网、OTN骨干网)/城域网【含3G/4G/5G接入网/PON接入网/OTN接入网+OTN/IP城域网+其他】/中心云(多/双/单Region+多AZ/双AZ/单AZ)+边缘DC+边缘计算节点+端计算节点包括IoT传感器、移动终端、CPE设备。通过5G NR(n78频段,带宽100MHz,子载波间隔30kHz)或GPON(下行2.5Gbps,上行1.25Gbps)接入。本地缓存小于10GB,主要用于临时数据暂存。位于地市级机房,部署MEC服务器(Intel Xeon Platin

weixin_49199313的博客 1327

【信息科学与工程学】【研发体系】第十篇 半导体电路设计 126 光学光刻、计算光刻 第一部分

用于全芯片修正的快速三维掩模近似模型(边界层模型、薄掩模近似改进)。:用于模型校准的测试图形设计(包含各种宽度、间距、方向的图形);扫描电镜、光学散射仪等量测数据的处理与模型拟合;模型误差的分解与追踪;:反演光刻技术的数学框架与求解算法(梯度法、像素翻转、水平集法);基于模型的OPC中边缘放置误差片段的智能移动策略;热点检测与分类的深度学习模型;:交替型、衰减型、无铬型等不同类型PSM的原理、制造与应用;光刻胶模型与显影模型的建立与校准。扫描电镜、散射仪等量测数据的处理与模型拟合;:厚掩模的电磁场仿真;

weixin_49199313的博客 1047

51c大模型~合集110

为了解决这一问题,在稠密化过程中,我们对容易引起退化和梯度集中的具有极端延展率的高斯面片进行了筛选,并对其增殖过程进行了限制,从而在不牺牲性能的情况下有效稳定了训练过程,保障了优化过程的顺利进行。大规模场景的重建往往还意味着显著的训练开销,要重建 1.97 平方千米的区域会产生接近两千万的高斯点,这意味着 4.6G 的存储以及 31.5G 的显存开销,以及超过三小时的训练时长。站在 AI 研究者的角度,得到了《苦涩的教训》,意味着在总结教训的过程中明确了什么是「更好」的。第二类则瞄准了相对复杂的问题。

whaosoft~aiotの开发板商城 2602

【信息科学与工程学】计算机科学与自动化 第二百零一十一 软件开发模型01

编号类型模型领域模型中的知识点/因素/参数关联知识和法律法规1传统顺序模型瀑布模型 (Waterfall)通用软件开发、硬件紧密耦合系统、政府/军工项目、需求稳定的传统信息系统严格线性阶段:可行性研究→需求分析(SRS,含功能/非功能/接口/约束,使用IEEE 830模板)→系统设计(概要设计HLD:架构、模块划分、数据库ER图;详细设计LLD:伪代码、类图、接口定义)→实现(编码规范、代码审查、静态分析工具SonarQube)→测试(单元测试JUnit、集成测试、系统测试、验收测试UAT,测试计划提前编写

weixin_49199313的博客 144

11-01-演进-.NET GC发展史

.NET GC发展史映射硬件演进:从单核STW到多核并发,再到区域化细粒度回收。历经分代管理、ServerGC、BackgroundGC、LOH自动压缩、POH隔离、DATC自适应线程数及Region-based管理等关键革新,代码量从5000行增至4万+,复杂度指数上升。每一步优化均在暂停时间、吞吐量与资源开销间权衡,体现“实用主义”哲学。核心启示:GC演进由硬件驱动,方向明确——更短暂停、更高效率,但代价是工程复杂性持续攀升。

设计 AI 玩游戏🎮 347

TI DSP从COFF切换到EABI输出格式的5个关键修改点(TMS320F280025实测)

本文基于TMS320F280025实测,详细解析了TI DSP从COFF切换到EABI输出格式的5个关键修改点。核心差异在于EABI遵循ELF标准,涉及链接器优化、RAM数据共享、工具链升级、double数据类型位宽变化及链接器命令文件重构。迁移时需使用.retain指令防止关键数据被优化,利用NOINIT段保护共享RAM,并更新hex2000等工具,以确保BootLoader与应用程序稳定运行。

weixin_29189381的博客 265

深入解析MTK DRM初始化流程:从KMS模块到组件框架

本文深入解析了联发科(MTK)平台上DRM显示框架的初始化流程。从内核模块加载、Component框架管理依赖,到核心的mtk_drm_bind函数构建KMS对象(CRTC、Plane、Encoder、Connector),最终完成DRM设备注册并创建用户空间接口。文章结合调试经验,为开发者梳理了从驱动启动到屏幕点亮的完整路径与关键排查点。

onion的博客 765

.NET 10 的性能提升

你不需要重写代码去用Span<T>,不需要手工池化对象,甚至不需要调整 GC 配置。JIT 编译器变得更“聪明”了,它会在编译时替你完成一些过去需要手动干预的优化。但与此同时,.NET 10 也引入了一个默认开启的 GC 行为变化,它在某些场景下会。这篇文章想讲清楚:哪些性能是你“自动”拿到的,哪些是需要你主动审视和取舍的。

qq_41019429的博客 332

极速建站!用1Panel面板一键部署Halo博客的保姆级教程 | 企业官网/个人博客搭建教程

个人博客是一种在互联网上发布自己的文章、图片、视频等内容的平台,通常以文字为主要形式,但也可以包含其他媒体。个人博客的用途非常广泛。它可以用来记录博主的日常生活、分享自己的知识和经验、展示自己的作品和技能,以及交流自己的观点和看法。通过个人博客,博主可以与读者建立联系,分享自己的见解和体验,同时也可以从读者那里获得反馈和建议。

zeruns的博客 1831

.NET 11 - 尝试一下Blazor中的新特性SupplyParameterFromTempData

时光匆匆,.NET Conf 2026大会将会在2026年11月份举办(11/10-11/13),到时微软将会发布.NET11,这是一个STS版本(Standard Term Support), 微软提供两年支持。当前.NET 11已经处于RC3版本(Release Candidate 3),很多新特性已经被发布出来了。

limingdinghao的博客 211

rk3399开发环境的介绍

由于Bluez的介绍文档有限,以及对Linux 系统/驱动概念、D-Bus 通信和蓝牙协议都有要求,加上网络上其实没有一个完整的介绍Bluez系列的文档,所以不管是蓝牙初学者还是蓝牙从业人员,都有不小的难度,学习曲线也相对较陡,所以我有了这个想法,专门对Bluez做一个系统性的介绍,尽可能的涵盖所有内容。

朝气蓬勃 708

手把手教你学simulink(11.6)--Simulink 航空航天场景:基于Simulink的飞机俯仰控制系统的数学模型

自动驾驶系统在航空航天领域具有重要应用,特别是在商业航空、军用航空和无人机等领域。PID控制器因其简单且有效的特性,被广泛应用于飞行控制。Simulink提供了一个强大的平台,用于建模、仿真和分析动态系统,非常适合设计和测试自动驾驶系统的控制器。通过本项目的实施,我们成功设计和仿真了一个用于控制飞机俯仰角的PID控制器。该项目展示了从系统建模、控制器设计、仿真验证到结果分析的完整流程,为PID控制器的设计提供了有价值的参考。希望这个实例能够为你的航空航天项目提供有用的指导。

MHD0815的博客 565
上一篇: 谈谈.NET中的内存管理
下一篇: 我的COM学习笔记
sam1111
博客等级 码龄26年 18粉丝 28原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值