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);
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);
var myObj = eval(“ new “ + className);
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)
}
... {
public abstract Object CreateObject(Object[] param);
private staticvoid CreateMethod(TypeBuilder tb, Type originalType, Object[] param);
public static Object New(Type type, params Object[] param)
}
New方法里面首先要动态的创建程序集和模块:
AssemblyBuilder dynamicAssembly
=
AppDomain.CurrentDomain.DefineDynamicAssembly(
new
AssemblyName(
"
DynamicAssembly
"
), AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = dynamicAssembly.DefineDynamicModule( " MainModule " );
ModuleBuilder moduleBuilder = dynamicAssembly.DefineDynamicModule( " MainModule " );
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);
CreateMethod(tb, type, param);
Creator creator = (Creator)Activator.CreateInstance(tb.CreateType());
return creator.CreateObject(param);
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)
ConstructorInfo theCi = null ;
ParameterInfo[] cpis = null ;
foreach (ConstructorInfo ci in cis)