如何通过动态lambda和IL创建一个对象的新实例?
如何通过动态lambda和IL创建一个对象的新实例?
问题出现的原因是想要通过动态lambda和IL来创建一个对象的新实例。解决方法是使用Expression.New()来表示对象的创建。可以传递一个没有参数的构造函数的Type,或者一个ConstructorInfo以及表示构造函数参数的Expression。如果希望返回一个object,并且希望它也适用于值类型,还需要添加一个Expression.Convert()。将所有这些组合在一起,相当于Activator.CreateInstance()的代码如下:
object CreateInstance(Type type) { return Expression.Lambda>( Expression.Convert(Expression.New(type), typeof(object))) .Compile()(); }
如果想要使用IL来实现相同的功能,对于引用类型,需要使用newobj指令。对于值类型,可以创建一个该类型的局部变量,对其进行装箱并返回。代码如下:
object CreateInstance(Type type) { var method = new DynamicMethod("", typeof(object), Type.EmptyTypes); var il = method.GetILGenerator(); if (type.IsValueType) { var local = il.DeclareLocal(type); // method.InitLocals == true, so we don't have to use initobj here il.Emit(OpCodes.Ldloc, local); il.Emit(OpCodes.Box, type); il.Emit(OpCodes.Ret); } else { var ctor = type.GetConstructor(Type.EmptyTypes); il.Emit(OpCodes.Newobj, ctor); il.Emit(OpCodes.Ret); } return method.Invoke(null, null); }
关于Expression的学习,你可以在MSDN上找到关于各种.Net类型的所有需要的信息,包括Expression的文档。并且,可以使用Expression.Constant()将构造函数的参数作为New()方法的参数进行传递。