基于动态代码生成技术的动态对象工厂

本文探讨了在无法直接使用new操作符时,动态代码生成技术在创建对象上的应用。虽然这种方法比直接new慢15-40倍,但相比Activator和Invoke方法,速度分别快20倍和10倍,证明其在特定场景下的实用性。
摘要由CSDN通过智能技术生成
 
C#中所有的引用类型的实例都需要在运行时动态创建,创建对象实例最常见的办法就是使用new操作符,使用new操作符就需要在编译器明确的知道要创建的对象的类型,如果在编译器并不能明确,就需要用到反射技术,例如:
            String className  =   " MyNamesapce.MyClass " ;
            ConstructorInfo ci 
=  Type.GetType(className).GetConstructor( new  Type[ 0 ]);
            Object o1 
=  ci.Invoke();
            Object o2 
=  Activator.CreateInstance(Type.GetType(className);
上述代码展示了两种基于反射的动态对象创建,但这种方法的效率是比较低下的,特别是在需要大量的动态创建实例的时候。为此我们需要一种更为高效的动态创建实例的方法,动态代码生成就是一种不错的方式。
之所以不能直接使用new,就是因为new后面的类型参数在编译器是不知道的,那么就需要在运行的时候动态的创建出与new相配合的代码。这类似于在Javascript中使用eval函数:
var  className  =  “MyClass”;
        
var  myObj  =  eval(“ new  “  +  className);
C#并没有像eval这样的函数,毕竟编译型语言和脚本语言是不同的,所以要实现类似的功能,就要使用到System.Reflection.Emit名空间下的类来动态的创建出可执行的代码。首先需要认识几个涉及到的类:
System.Reflection.Emit.AssemblyBuilder:用来动态创建程序集
System.Reflection.Emit.ModuleBuilder:用来动态创建模块
System.Reflection.Emit.TypeBuilder:用来动态创建类型
System.Reflection.Emit.MethodBuilder:用来动态创建方法
这里我的设计思想是,首先创建一个抽象基类(Creator类),它声明了一个用于动态创建需要的对象实例的抽象方法,在运行时根据需要动态的创建出这个抽象类的子类,并动态实现这个抽象方法,编写出用于创建对象的代码。在基类中提供一些静态方法来实现子类的创建过程,并对外提供可调用的方法。这是抽象工厂模式的一种实现。基类的声明如下:
public   abstract   class  Creator
{
        
public abstract Object CreateObject(Object[] param);
        
private staticvoid CreateMethod(TypeBuilder tb, Type originalType, Object[] param);
        
public static Object New(Type type, params Object[] param) 
}

抽象方法CreateObject就是用来在子类中重写并创建实例的,静态方法CreateMethod用于实现动态代码生成的过程,静态方法New就是对象暴露的方法,使用者通过这个方法来创建需要的实例,从而模拟new操作符,它的两个参数分别代码要创建的变量的类对象、构造函数的参数,这里使用了关键字params来修释,也就是说它成为一个参数个数可变的函数,可以适应各种参数类型的构造函数。
New方法里面首先要动态的创建程序集和模块:
AssemblyBuilder dynamicAssembly  =  AppDomain.CurrentDomain.DefineDynamicAssembly( new  AssemblyName( " DynamicAssembly " ), AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder 
=  dynamicAssembly.DefineDynamicModule( " MainModule " );
参数AssemblyBuilderAccess.Run表示这个动态创建的程序集只用于执行,而不需要保存。有了程序集和模块之后就需要创建Creator类的子类了,也就是工厂类:
TypeBuilder tb  =  moduleBuilder.DefineType( " __dynamicCreator. "   +  type.FullName, TypeAttributes.Public  |  TypeAttributes.Class,  typeof (Creator));
CreateMethod(tb, type, param);
Creator creator 
=  (Creator)Activator.CreateInstance(tb.CreateType());
return  creator.CreateObject(param);
这里动态工厂类的类名与要创建的对象的类名相同,名空间前面加上了“__dynamicCreator.”以示区别,参数typeof(Creator)表示这个类要从Creator类继承。然后调用CreateMethod方法来完成动态代码生成,然后调用TypeBuilder的CreateType方法,它会根据之前动态创建的代码生成一个新的类,并在之后可以立即使用,然后我使用Activator.CreateInstance创建出工厂类的实例,之后就可以通过调用这个实例的CreateObject方法来创建出需要的对象了。需要说明的是这里的代码只是一个示例,真正要使用时还需要对创建出的creator对象进行缓存,以后再次创建相同类型的对象时就可以直接使用它的creator对象了。CreateMethod方法是最核心的地方,它需要根据我们指定的类对象和参数找到适当的构造函数,动态为工厂类创建CreateObject方法,在其中调用找到的构造函数,返回构造出的对象。首先得到基类中抽象方法CreateObject的信息:
MethodInfo mi  =   typeof (Creator).GetMethod( " CreateObject " );
然后根据这个方法信息创建出子类的同名方法:
MethodBuilder mb  =  tb.DefineMethod( " CreateObject " , mi.Attributes  &   ~ MethodAttributes.Abstract, mi.CallingConvention, mi.ReturnType,  new  Type[]  typeof(Object[]) } );
注意这里指定方法属性时需要去除掉基类方法的抽象属性,否则在创建实例时会失败,其他地方都完全和基类方法一样。下面要在被创建对象的类型中查找适当的构造函数。查找的方法是针对每一个构造函数,检查它的参数个数和参数类型与所传入的参数信息是否相容,如果找不到完全相容的构造函数,那么说明用户传入的参数有误,需要抛出异常:
ConstructorInfo[] cis  =  originalType.GetConstructors();  // 反射出所有的构造函数
ConstructorInfo theCi  =   null ;
ParameterInfo[] cpis 
=   null ;
foreach (ConstructorInfo ci  in  cis)
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值