Как создать новый экземпляр объекта с помощью динамической лямбды и IL? - PullRequest
1 голос
/ 03 апреля 2012

Я знаю, что Activator.CreateInstance() может создать новый экземпляр object. Но я ищу способ создать экземпляр с помощью IL и Expression. Я думаю, что могу создать динамическую лямбду, чтобы создать экземпляр типа, и кэшировать лямбда, чтобы ускорить инициализацию объектов. Я прав? Можете ли вы помочь мне, пожалуйста?

1 Ответ

4 голосов
/ 03 апреля 2012

Вы можете представить создание объекта, используя Expression.New(). Вы можете передать ему либо Type, который имеет конструктор без параметров, либо ConstructorInfo вместе с Expression s, представляющими параметры конструктора. Если вы хотите вернуть object и хотите, чтобы он работал и для типов значений, вам также необходимо добавить Expression.Convert().

Если сложить все вместе, эквивалент Activator.CreateInstance() может выглядеть так:

object CreateInstance(Type type)
{
    return Expression.Lambda<Func<object>>(
        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);
}
...