C#中所有的引用类型的实例都需要在运行时动态创建,创建对象实例最常见的办法就是使用new操作符,使用new操作符就需要在编译器明确的知道要创建的对象的类型,如果在编译器并不能明确,就需要用到反射技术,例如:
之所以不能直接使用new,就是因为new后面的类型参数在编译器是不知道的,那么就需要在运行的时候动态的创建出与new相配合的代码。这类似于在Javascript中使用eval函数:
System.Reflection.Emit.AssemblyBuilder:用来动态创建程序集
System.Reflection.Emit.ModuleBuilder:用来动态创建模块
System.Reflection.Emit.TypeBuilder:用来动态创建类型
System.Reflection.Emit.MethodBuilder:用来动态创建方法
这里我的设计思想是,首先创建一个抽象基类(Creator类),它声明了一个用于动态创建需要的对象实例的抽象方法,在运行时根据需要动态的创建出这个抽象类的子类,并动态实现这个抽象方法,编写出用于创建对象的代码。在基类中提供一些静态方法来实现子类的创建过程,并对外提供可调用的方法。这是抽象工厂模式的一种实现。基类的声明如下:
New方法里面首先要动态的创建程序集和模块:
AssemblyBuilderdynamicAssembly=AppDomain.CurrentDomain.DefineDynamicAssembly(newAssemblyName("DynamicAssembly"),AssemblyBuilderAccess.Run);
ModuleBuildermoduleBuilder=dynamicAssembly.DefineDynamicModule("MainModule");
参数AssemblyBuilderAccess.Run表示这个动态创建的程序集只用于执行,而不需要保存。有了程序集和模块之后就需要创建Creator类的子类了,也就是工厂类:
MethodInfomi=typeof(Creator).GetMethod("CreateObject");
然后根据这个方法信息创建出子类的同名方法:
MethodBuildermb=tb.DefineMethod("CreateObject",mi.Attributes&~MethodAttributes.Abstract,mi.CallingConvention,mi.ReturnType,newType[]...{typeof(Object[])});
注意这里指定方法属性时需要去除掉基类方法的抽象属性,否则在创建实例时会失败,其他地方都完全和基类方法一样。下面要在被创建对象的类型中查找适当的构造函数。查找的方法是针对每一个构造函数,检查它的参数个数和参数类型与所传入的参数信息是否相容,如果找不到完全相容的构造函数,那么说明用户传入的参数有误,需要抛出异常:
if(cpis[i].ParameterType.IsValueType)//判断是否需要拆箱
ilg.Emit(OpCodes.Unbox_Any,cpis[i].ParameterType);//拆箱为需要的类型
}
Unbox操作也会自动从栈中取出一个元素,拆箱后再把结果放回栈中,也就是说上述过程不会影响栈中元素的个数。经过上述过程,构造函数的参数就已经准备好并放入栈中了,下面就是调用构造函数了:
ilg.Emit(OpCodes.Newobj,theCi);
指令Newobj相当于关键字new,用于调用构函数,参数theCi就是要创建的对象的构造函数信息。经过这个过程原栈中所压的构造函数参数都被弹出,然后把创建后的对象放回到栈中。下面只需要通过Ret指令就可以把栈中唯一的元素作为函数的返回值返回给调用者:
ilg.Emit(OpCodes.Ret);
到这里所需要的代码就已经动态生成完毕,以后再通过Creator类的子类调用CreateObject方法时,执行的就是上述动态生成的代码了。但只有这些还不够,Creator子类的虚方法表还没有更新,需要调用TypeBuilder类的DefineMethodOverride方法明确的指出用子类中的方法覆盖基类中的虚方法:
tb.DefineMethodOverride(mb,mi);//定义方法重载
这段代码虽然比直接使用反射技术要复杂很多,而且里面也多处使用了反射技术,但它只有在第一次使用时被调用到,之后就只调用动态生成的代码,因此对性能影响是可以忽略的。
下面就是要使用上述代码了。假如我们有一个类如下:
StringclassName="MyClass";
Typet=Type.GetType(className);
Objecto=Creator.New(t,1,"haha");
用起来还是比较方便的,至少不比反射麻烦。
为了进一步研究这种方法相对于反射方法的优势,我进行了一组实验。首先构造一个类,它有六个构造函数,分别用于测试一个、三个、九个值类型、引用类型参数时的性能:
publicclassA
...{
publicA(strings,strings2,strings3,strings4,strings5,strings6,strings7,strings8,strings9)...{}
publicA(strings,strings2,strings3)...{}
publicA(strings)...{}
publicA(inta,intb,intc,intd,inte,intf,intg,inth,inti)...{}
publicA(inta,intb,intc)...{}
publicA(inta)...{}
}
然后通过四种方式调用这六个构造函数来创建实例:Activator.CreateInstance、ConstructorInfo.Invoke、Creator.New、直接使用new,每种调用都重复1000万次,在Intel PentiumM 1.86G、512M内存、Windows XP SP2、.Net Framewor 2.0上测试结果如下:
各种调用类型重复1000万次所需时间(毫秒)
调用方式
|
Activator.
CreateInstance
|
ConstructorInfo.
Invoke
|
Creator.New
|
直接使用new
|
引用类型
|
1个参数
|
59281.25
|
18843.75
|
2296.875
|
140.625
|
3个参数
|
72031.25
|
24000
|
2453.125
|
171.875
|
9个参数
|
102843.75
|
39218.75
|
3187.5
|
156.25
|
值类型
|
1个参数
|
60468.75
|
19921.875
|
2375
|
109.375
|
3个参数
|
73953.125
|
26390.625
|
2796.875
|
109.375
|
9个参数
|
110656.25
|
46765.625
|
4453.125
|
109.375
|
可见,直接使用new还是最快的,动态代码生成的方法还是要比直接使用new慢了15-40倍,但比使用Activator的方法快20倍左右,比Invoke的方法快10倍左右,因此在不能直接使用new的时候,动态代码生成的方法还是非常实用的。
附完整的源代码如下。此代码仍有一些问题,如当一个类有多个构造函数时,它只能缓存一个构造函数,第二次如果调用另一个则会出错,可以适当的改进来解决此问题。
相关推荐
动软代码生成器是一款完全自主知识产权研发的为软件项目开发设计的自动代码生成器,也是一个软件项目智能开发平台,它可以生成基于面向对象的思想和三层架构设计的代码,结合了软件开发中经典的思想和设计模式,融入...
".NET代码生成器"能生成工厂模式的类结构,意味着它可以自动生成负责创建对象的工厂类,以及与之相关的接口和具体产品类。这不仅减轻了开发者的编码负担,也使代码结构更加清晰,符合SOLID原则,有利于后续的重构和...
总的来说,这个“工厂模式代码生成器”是一个基于工厂模式理念设计的工具,它结合了 Common.dll 和 DBUtility.dll 等库文件,提供了代码生成服务。通过 CodeGeneration.exe 这个执行入口,用户可以方便地自定义参数...
Net代码生成器Codematic 是一款为C#数据库程序员设计的自动代码生成器,Codematic 生成的代码基于面向对象的思想和三层架构设计,结合了Petshop中经典的思想和设计模式,融入了工厂模式,反射机制等等一些思想。...
动软.Net代码生成器Codematic 是一款为C#数据库程序员设计的自动代码生成器,Codematic 生成的代码基于面向对象的思想和三层架构设计,结合了Petshop中经典的思想和设计模式,融入了工厂模式,反射机制等等一些思想...
动软代码生成工具会根据这一模式生成相应的工厂类和接口,使得业务逻辑层能够更方便地获取和操作数据访问层的对象。 此外,动软代码生成工具采用了PetShop4.0的架构思想。PetShop4.0是一个经典的.NET示例应用,展示...
4. **设计模式**:代码生成通常涉及设计模式,如工厂模式、策略模式等,理解这些模式可以帮助你更好地组织代码生成器的架构。 通过深入学习和实践,你可以将这个C#代码生成器定制为适合你项目需求的工具,无论是...
动软.Net代码生成器Codematic 是一款为C#数据库程序员设计的自动代码生成器,Codematic 生成的代码基于面向对象的思想和三层架构设计,结合了Petshop中经典的思想和设计模式,融入了工厂模式,反射机制等等一些思想...
通过自动化的代码生成,它能够帮助开发者快速构建基于设计模式的应用程序,减轻重复劳动,让开发者有更多时间专注于业务逻辑和创新功能的实现。 设计模式是软件工程中的重要概念,它们是经过验证的、在特定上下文中...
此外,对于遵循特定设计模式(如工厂模式、策略模式等)的项目,代码生成器也能提供便捷的解决方案。 "CC代码生成器"作为压缩包中的核心文件,很可能是这个工具的执行程序或者配置文件。使用时,开发人员可能需要...
动软.Net代码生成器 是一款为C#数据库程序员设计的自动代码生成器,Codematic 生成的代码基于面向对象的思想和三层架构设计,结合了Petshop中经典的思想和设计模式,融入了工厂模式,反射机制等等一些思想。...
9.Net代码生成器Codematic 是一款为C#数据库程序员设计的自动代码生成器,Codematic 生成的代码基于面向对象的思想和三层架构设计,结合了Petshop中经典的思想和设计模式,融入了工厂模式,反射机制等等一些思想。...
Codematic 是一款为 C# 数据库程序员设计的自动代码生成器,Codematic 生成的代码基于基于面向对象的思想和三层架构设计,结合了Petshop中经典的思想和设计模式,融入了工厂模式,反射机制等等一些思想。采用 Model ...
是一款完全自主知识产权研发的为软件项目开发设计的自动代码生成器,也是一个软件项目智能开发平台,它可以生成基于面向对象的思想和三层架构设计的代码,结合了软件开发中经典的思想和设计模式,融入了工厂模式,...
动软.Net代码生成器Codematic是一款为C#数据库程序员设计的自动代码生成器,Codematic生成的代码基于面向对象的思想和三层架构设计,可以直接生成三层架构的项目的代码,使程序员可以节省大量机械录入的时间和重复...
动软.Net代码生成器Codematic 是一款为C#数据库程序员设计的自动代码生成器,Codematic 生成的代码基于面向对象的思想和三层架构设计,结合了Petshop中经典的思想和设计模式,融入了工厂模式,反射机制等等一些思想...
C# 2.0 代码生成器正是这样一种工具,它基于工厂模式设计,旨在帮助开发者快速生成符合规范的代码,避免手动编写大量重复的模板代码。本文将深入探讨这一工具的核心概念、实现原理以及实际应用。 一、代码生成器...
动软.Net代码生成器Codematic 是一款为C#数据库程序员设计的自动代码生成器,Codematic 生成的代码基于面向对象的思想和三层架构设计,结合了Petshop中经典的思想和设计模式,融入了工厂模式,反射机制等等一些思想...
动软代码生成器 是一款为程序员设计的全功能自动代码生成器,也是一个智能化软件开发平台, 它可以生成基于面向对象的思想和三层架构设计的代码,结合了软件开发中经典的思想和设计模式, 融入了工厂模式,反射机制...