Используя Делегата для вызова конструктора

Я нашел это, но попытался использовать его и отказавший.

Как я могу создать объект с помощью отражений и сделать его быстро путем помещения его в делегата?

        DynamicMethod dm = new DynamicMethod("MyCtor", t, new Type[] { });            
        var ctor = t.GetConstructor(new Type[] { });
        ILGenerator ilgen = dm.GetILGenerator();
        ilgen.Emit(OpCodes.Ldarg_0);
        ilgen.Emit(OpCodes.Newobj, ctor);
        ilgen.Emit(OpCodes.Ret);
        var d = (Func)dm.CreateDelegate(t);
        dm.Invoke(null, new object[] { });

Прежде, чем поместить его в deleage я пытался, по крайней мере, вызвать его и когда я сделал выше, я получаю ошибку

An unhandled exception of type 'System.Reflection.TargetInvocationException' occurred in mscorlib.dll

Дополнительная информация: Исключение было выдано целью вызова.

Если я называю d () вместо этого, я получаю исключение

An unhandled exception of type 'System.ArgumentException' occurred in mscorlib.dll

Additional information: Type must derive from Delegate.

Как я не помещаю конструктора параметрического усилителя в делегата и называю его?

6
задан 12 January 2010 в 18:27
поделиться

3 ответа

почему он существует то.

Он существует для классов, в которых вы заботитесь об их жизни, в частности, когда класс переносит ресурс в ОС и вы хотите выпустить его немедленно. В противном случае потребуется дождаться завершения CLR (недетерминированного).

Примеры, дескрипторы файлов, подключения к БД, подключения к сокетам,....

-121--3832538-

Специально для веб-разработки, приобретая навыки работы с C #, стало намного проще писать javascript (и делать сложные вещи с помощью jQuery), потому что синтаксис так похож.

-121--3926545-

Если у вас есть доступ к .NET 3,5 (что предлагает использование Func < T > ), вы можете найти выражение Expression проще, чем ILGenerator :

class Foo { }
static void Main() {
    Func<Foo> func = GetCtor<Foo>(); // cache this somewhere!
    Foo foo = func();
}
static Func<T> GetCtor<T>() {
    Type type = typeof(T);
    Expression body = Expression.New(type);
    return Expression.Lambda<Func<T>>(body).Compile();        
}

Довольно легко расширить его для использования конкретного конструктора, передачи аргументов или добавления свойства постконструктора слепки, преобразования и т.д. (см. этот связанный ответ ). Если у вас есть конкретный сценарий, я с радостью добавлю пример.

Также обратите внимание, что следует кэшировать и повторно использовать любые такие конструкторы - в противном случае вы потеряете преимущество (т.е. не будете повторно создавать делегат для каждого вызова).

11
ответ дан 8 December 2019 в 16:03
поделиться

Попробуйте это -

Action myCtor = CreateCtor(t, Type.EmptyTypes, typeof(Action));

public static Delegate CreateCtor(Type type, Type[] parameterTypes, Type delegateType, string typeParameterName)
{
    var ctorInfo = type.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, parameterTypes, null);
    if (ctorInfo == null)
    {
        string parameterString = string.Empty;
        if(parameterTypes.Length > 0)
        {
            string[] parameterStrings = new string[parameterTypes.Length];
            for(int i = 0; i < parameterTypes.Length; ++i)
            {
                parameterStrings[i] = parameterTypes[i].ToString();
            }
            parameterString = string.Join(",", parameterStrings);
        }
        throw new ArgumentException(string.Format("Type '{0}' does not define .ctor({1}).", type, parameterString), typeParameterName);
    }

    bool isVisible = type.IsVisible && (ctorInfo.IsPublic && !ctorInfo.IsFamilyOrAssembly);

    DynamicMethod dynamicCtor = new DynamicMethod(Guid.NewGuid().ToString("N"), type, parameterTypes, ctorInfo.Module, !isVisible);
    var il = dynamicCtor.GetILGenerator();
    for (int i = 0; i < parameterTypes.Length; ++i)
    {
        switch (i)
        {
            case 0: il.Emit(OpCodes.Ldarg_0); break;
            case 1: il.Emit(OpCodes.Ldarg_1); break;
            case 2: il.Emit(OpCodes.Ldarg_2); break;
            case 3: il.Emit(OpCodes.Ldarg_3); break;
            default: il.Emit(OpCodes.Ldarg, i); break;
        }
    }
    il.Emit(OpCodes.Newobj, ctorInfo);
    il.Emit(OpCodes.Ret);
    return dynamicCtor.CreateDelegate(delegateType);
}
4
ответ дан 8 December 2019 в 16:03
поделиться

В конструкторе нет аргументов, чтобы вы не должны загружать аргументы в стеке ilgen.emit (OPCodes.ldarg_0) :

class Program
{
    static void Main()
    {
        var t = typeof(Program);
        var dm = new DynamicMethod("MyCtor", t, new Type[0], t.Module);
        var ctor = t.GetConstructor(new Type[0]);
        ILGenerator ilgen = dm.GetILGenerator();
        ilgen.Emit(OpCodes.Newobj, ctor);
        ilgen.Emit(OpCodes.Ret);
        var del = (Func<Program>)dm.CreateDelegate(typeof(Func<Program>));
        var instance = del();
        Console.WriteLine(instance);
    }
}
0
ответ дан 8 December 2019 в 16:03
поделиться
Другие вопросы по тегам:

Похожие вопросы: