Создает делегата из MethodInfo?

После поиска в Google и посадки на SO и прочитавэтот другой вопрос

Is it possible to build a correct Delegate from a MethodInfo if you didn't know the number or types of parameters at compile time?

Подробнее об этом: можно ли сделать это элегантно без использования Reflection.Emit или компоновщиков типов?

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

Я строю несколько снастей для ниндзя, и это очень поможет ... Спасибо!

Here's a generic solution:

/// <summary>
/// Builds a Delegate instance from the supplied MethodInfo object and a target to invoke against.
/// </summary>
public static Delegate ToDelegate(MethodInfo mi, object target)
{
    if (mi == null) throw new ArgumentNullException("mi");

    Type delegateType;

    var typeArgs = mi.GetParameters()
        .Select(p => p.ParameterType)
        .ToList();

    // builds a delegate type
    if (mi.ReturnType == typeof(void)) {
        delegateType = Expression.GetActionType(typeArgs.ToArray());

    } else {
        typeArgs.Add(mi.ReturnType);
        delegateType = Expression.GetFuncType(typeArgs.ToArray());
    }

    // creates a binded delegate if target is supplied
    var result = (target == null)
        ? Delegate.CreateDelegate(delegateType, mi)
        : Delegate.CreateDelegate(delegateType, target, mi);

    return result;
}

NoteЯ создаю приложение Silverlight, которое заменит встроенное приложение javascript много лет назад, в котором у меня есть несколько интерфейсов Javascript, которые вызывают один и тот же метод Silverlight [ScriptableMember].

Необходимо поддерживать все эти устаревшие JS-интерфейсы, а также новый интерфейс для доступа к новым функциям, что автоматически настраивает JS-интерфейс и «делегирует». вызов правильного метода Silverlight поможет значительно ускорить работу.

Я не могу разместить здесь код, так что это краткое изложение.

Ответы на вопрос(3)

Почему это сложно?

public static Delegate CreateDelegate(this MethodInfo method)
{
    return Delegate.CreateDelegate
    (
        Expression.GetDelegateType
        (
            method.GetParameters()
                .Select(p => p.ParameterType)
                .Concat(new Type[] { method.ReturnType })
                .ToArray()
        ),
        null,
        method
    );   
}

[Примечание: у меня есть префикс этого метода & quot; Создать ... & quot ;. & Quot; К ... & Quot; сбивает с толку, так как вводит вас в заблуждение думать, что это обращение.]

 29 дек. 2010 г., 18:45
Передавая объект в качестве второго параметра (называемого «firstArgument» - здесь я передаю ноль), вы можете указать объект, с которым связан делегат. Или я упускаю суть?
 chakrit28 дек. 2010 г., 23:34
Expression.GetDelegateType Метод на самом деле специфичен для .NET 4 и SL 4. Мой вопрос был задан до выпуска .NET4 и SL4. В любом случае спасибо за ответ. Обратите внимание, что вам нужно будет привязать делегат к цели, если метод является методом экземпляра, поэтому обязательная часть все еще обязательна.
Решение Вопроса

Если честно, если вы не знаете тип во время компиляции, то не будет огромного количества преимуществ в созданииDelegate, Вы не хотите использоватьDynamicInvoke; это будет примерно так же медленно, как отражение. Основным исключением является случай, когда в тени скрывается тип делегата, например, при подписке на событие - в этом случаеEventInfo делает это доступным

Для информации, в .NET 3.5 наExpression, есть:

Expression.GetActionType(params Type[] typeArgs);
Expression.GetFuncType(params Type[] typeArgs)

Это может помочь до такой степени:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
static class Program {
    static void Main() {
        DoStuff("Test1");
        DoStuff("Test2");
    }
    static void DoStuff(string methodName) {
        MethodInfo method = typeof(Program).GetMethod(methodName);
        List<Type> args = new List<Type>(
            method.GetParameters().Select(p => p.ParameterType));
        Type delegateType;
        if (method.ReturnType == typeof(void)) {
            delegateType = Expression.GetActionType(args.ToArray());
        } else {
            args.Add(method.ReturnType);
            delegateType = Expression.GetFuncType(args.ToArray());
        }
        Delegate d = Delegate.CreateDelegate(delegateType, null, method);
        Console.WriteLine(d);
    }
    public static void Test1(int i, DateTime when) { }
    public static float Test2(string x) { return 0; }
}
 chakrit14 июл. 2009 г., 12:39
Я строю это, чтобы склеить Silverlight [ScriptableMember] и отдельный интерфейс Javascript, поэтому мне не нужно беспокоиться о синхронизации сигнатур методов в обоих местах.
 18 дек. 2013 г., 14:45
Хорошо. Спасибо Марк Гравелл.
 18 дек. 2013 г., 14:13
@Saranya, чтобы вызвать егоquickly (с помощьюInvoke), вам нужно знать сигнатуру метода заранее, чтобы вы могли привести его к правильному типу - например,Action<Foo>илиFunc<Bar, string, int>.
 chakrit14 июл. 2009 г., 12:45
Вау .... это очень помогло! Вы, ребята, рок!
 18 дек. 2013 г., 13:01
@ Марк Грэвелл, я не могу вызвать делегата, созданного в приведенном выше коде, как d (). После поиска в Google я обнаружил, что dynamicInvoke может использоваться для вызова метода, который очень медленный. Пожалуйста, помогите. я новичок для делегатов и событий. мое требование - вызывать метод динамически, число или тип параметров будут известны только во время выполнения

Если вы не знаете заранее количество или тип параметров, возможно, это означает, что вы не знаете тип делегата, который хотите создать?

Если это так, вы застряли в абсолютно общем случае.

Однако для большинстваcommon случаев (без параметров ref / out, достаточно мало параметров, чтобы использовать один из существующих типов), вы можете обойтись без одного изFunc или жеAction делегаты. (.NET 4.0 имеетFunc/Action типы для огромного числа параметров, так что на самом деле вам нужно беспокоиться только о параметрах out / ref.) Если у метода есть возвращаемый тип, отличный от void, используйтеFuncиначе используйтеAction, Определите, какой тип использовать, исходя из количества параметров, например,

static readonly Type[] FuncTypes = { typeof(Func), 
    typeof(Func<>), typeof(Func<,>), typeof(Func<,,>), /* etc */ };

использованиеType.MakeGenericType используя типы параметров и возвращаемый тип, чтобы получить правильный тип делегата, затемDelegate.CreateDelegate должно сработать.

У меня нет времени, чтобы обработать образец прямо сейчас, но дайте мне знать, если вы хотите, чтобы я позже.

Один вопрос: как вы собираетесь использовать этот делегат? Что-то еще нужно знать, как выполнить это, конечно ...

 chakrit14 июл. 2009 г., 12:52
Я добавил "почему" на вопрос
 14 июл. 2009 г., 12:44
Чтобы избежать статического Типа [], рассмотрите Expression.GetActionType / Expression.GetFuncType - см. Пост. я мог быhope что эти методы были расширены, чтобы включить новые варианты .NET 4.0.
 chakrit14 июл. 2009 г., 12:36
ах-ха ... хороший пример для MakeGenericType + Func ... который бы это сделал :-)
 14 июл. 2009 г., 12:54
Круто - не знал о Expression.GetActionType / GetFuncType. Froody.

Ваш ответ на вопрос