从 MethodInfo 构建委托?

发布于 2024-07-27 02:48:29 字数 1639 浏览 4 评论 0原文

在谷歌搜索并登陆 SO 并阅读另一个问题之后

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

不使用 Reflection.Emit 或类型构建器?

这对我来说有点令人失望,因为 Delegate.CreateDelegate 要求我指定正确的委托类型作为第一个参数,否则它会抛出异常或调用不正确的方法。

我正在建造一些忍者装备,这会有很大帮助......谢谢!


这是一个通用解决方案:

/// <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 应用程序,其中我有多个 Javascript 接口调用相同的 Javascript 接口。 Silverlight [ScriptableMember] 方法。

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

我无法在这里发布代码,所以这就是摘要。

After googling and landing on SO and having read this other question

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?

More on this: can this be done elegantly without the use of Reflection.Emit or type builders?

This is sorta a bummer for me because Delegate.CreateDelegate requires me to specify the correct Delegate type as the first parameter or else it would throw exceptions or invoke an incorrect method.

I'm building some ninja gears and this would helps a lot... Thanks!


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: I am building a Silverlight application that would replace a built-years-ago javascript application in which I have multiple Javascript interfaces that calls into the same Silverlight [ScriptableMember] method.

All those legacy JS interfaces need to be supported as well as new interface for accessing new features, so something that automatically setups the JS interface and "delegates" the call to the right Silverlight method would helps speed up work a lot.

I can't post code here, so that's the summary.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

月竹挽风 2024-08-03 02:48:29

老实说,如果您在编译时不知道类型,那么创建 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; }
}

To be honest, if you don't know the type at compile time, there isn't a huge amount of benefit in creating a Delegate. You don't want to use DynamicInvoke; it will be about as slow as reflection. The main exception to this is when there is a delegate-type lurking in the shadows, for example when subscribing to an event - in which case EventInfo makes this available.

For info, in .NET 3.5 on Expression, there is:

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

That might help to an extent:

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; }
}
眼藏柔 2024-08-03 02:48:29

为什么这么复杂?

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...”令人困惑,因为它会误导您认为这是一种转变。]

Why that complicated?

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

[Side note: I prefixed this method "Create...". "To..." is confusingly as it misleds you to think it's a conversion.]

偏闹i 2024-08-03 02:48:29

如果您事先不知道参数的数量或类型,想必这意味着您也不知道要创建的委托类型?

如果是这种情况,那么您就陷入了绝对一般的情况。

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

我现在没有时间制作样品,但如果您稍后需要,请告诉我。

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

If you don't know the number or type of parameters in advance, presumably that means you don't know the delegate type you want to create either?

If that's the case, you're stuck in the absolutely general case.

However, for most common cases (no ref/out parameters, few enough parameters to use one of the existing types) you could get away with one of the Func or Action delegates. (.NET 4.0 has Func/Action types for huge numbers of parameters, so really you'd only need to worry about out/ref parameters.) If the method has a non-void return type use Func, otherwise use Action. Work out which type to use based on the number of parameters, e.g.

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

Use Type.MakeGenericType using the parameter types and return type to get the right delegate type, then Delegate.CreateDelegate should work.

I don't have time to work up a sample right now, but let me know if you want me to later on.

One question: how are you intending to use this delegate? Something else is going to need to know how to execute it, surely...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文