如何通过动态lambda和IL创建一个对象的新实例?

19 浏览
0 Comments

如何通过动态lambda和IL创建一个对象的新实例?

我知道Activator.CreateInstance()可以创建一个object的新实例。但是我正在寻找一种通过ILExpression来创建实例的方法。我认为我可以创建一个动态的lambda来创建一个类型的实例,并将lambda缓存起来以加速对象的初始化。我是对的吗?你能帮我吗?

0
0 Comments

如何通过动态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()方法的参数进行传递。

0