【问题标题】:Builds a Delegate from MethodInfo?从 MethodInfo 构建一个委托?
【发布时间】:2009-07-14 10:28:01
【问题描述】:

谷歌搜索并登陆 SO 并阅读 this other question

是否可以从 MethodInfo 构建正确的委托如果您在编译时不知道参数的数量或类型?

更多信息:不使用 Reflection.Emit 或类型生成器可以优雅地完成这项工作吗?

这对我来说有点令人沮丧,因为 Delegate.CreateDelegate 要求我将正确的 Delegate 类型指定为第一个参数,否则它会引发异常或调用不正确的方法。

我正在制作一些忍者装备,这对我很有帮助...谢谢!


这是一个通用的解决方案:

/// <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;
}

注意:我正在构建一个 Silverlight 应用程序,它将取代多年前构建的 javascript 应用程序,在该应用程序中,我有多个调用相同 Silverlight [ScriptableMember] 方法的 Javascript 接口。

需要支持所有这些遗留 JS 接口以及用于访问新功能的新接口,因此自动设置 JS 接口并“委托”对正确 Silverlight 方法的调用将有助于大大加快工作速度。

我不能在这里发布代码,所以这是摘要。

【问题讨论】:

    标签: .net reflection delegates methodinfo


    【解决方案1】:

    说实话,如果您在编译时不知道类型,那么创建Delegate 并没有太多好处。你不想使用DynamicInvoke;它将与反射一样慢。主要的例外是当代理类型潜伏在阴影中时,例如在订阅事件时 - 在这种情况下EventInfo 使其可用。

    有关信息,在 Expression 上的 .NET 3.5 中,有:

    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; }
    }
    

    【讨论】:

    • 我正在构建它以将 Silverlight [ScriptableMember] 和单独的 Javascript 接口粘合在一起,因此我不必担心在两个位置保持方法签名同步。
    • @Marc Gravell,我无法像 d() 那样调用在上述代码中创建的委托。谷歌搜索后,我发现可以使用 dynamicInvoke 来调用该方法,这很慢。请帮忙。我是代表和活动的新手。我的要求是动态调用方法,参数的数量或类型仅在运行时知道
    • @Saranya 调用它快速(通过Invoke),你需要提前知道方法的签名,以便你可以将它转换为正确的类型- 例如Action&lt;Foo&gt;,或Func&lt;Bar, string, int&gt;
    【解决方案2】:

    为什么这么复杂?

    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
        );   
    }
    

    [旁注:我为这个方法添加了前缀“创建...”。 “To...”很容易混淆,因为它会误导您认为这是一种转换。]

    【讨论】:

    • Expression.GetDelegateType 方法实际上是 .NET 4 和 SL 4 特定的。我的问题是在 .NET4 和 SL4 发布之前提出的。无论如何感谢您的回答。请注意,如果方法是实例方法,则需要将委托绑定到目标,因此绑定部分仍然是必需的。
    • 通过传递一个对象作为第二个参数(称为'firstArgument' - 我在这里传递null),您可以指定委托绑定到的对象。还是我没有抓住重点?
    【解决方案3】:

    如果你事先不知道参数的个数或类型,想必你也不知道要创建的委托类型吧?

    如果是这样,你就陷入了绝对一般的情况。

    但是,对于大多数常见 情况(没有 ref/out 参数,使用现有类型之一的参数足够少),您可以使用 FuncAction 代表之一. (.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 应该可以工作。

    我现在没有时间制作样本,但如果您希望我稍后再做,请告诉我。

    一个问题:你打算如何使用这个委托?当然,还有其他东西需要知道如何执行它......

    【讨论】:

    • ah-ha ... 对 MakeGenericType + Func 有很好的了解 ... 就可以了 :-)
    • 要避免使用静态类型 [],请考虑 Expression.GetActionType / Expression.GetFuncType - 请参阅帖子。我希望希望这些方法已扩展为包含新的 .NET 4.0 变体。
    • 我在问题中添加了“为什么”
    • 酷 - 不知道 Expression.GetActionType/GetFuncType。弗罗迪。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-03-02
    • 2011-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多