C# 当方法签名无法事先知道时,如何从 MethodInfo 创建委托?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16364198/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 00:52:04  来源:igfitidea点击:

How to create a delegate from a MethodInfo when method signature cannot be known beforehand?

c#.netreflectiondelegatesmethodinfo

提问by Zakharia Stanley

I need a method that takes a MethodInfoinstance representing a non-generic static method with arbitrary signature and returns a delegate bound to that method that could later be invoked using Delegate.DynamicInvokemethod. My first na?ve try looked like this:

我需要一个方法,它采用一个MethodInfo实例来表示一个具有任意签名的非通用静态方法,并返回一个绑定到该方法的委托,该委托稍后可以使用Delegate.DynamicInvoke方法调用。我的第一次尝试看起来像这样:

using System;
using System.Reflection;

class Program
{
    static void Main()
    {
        var method = CreateDelegate(typeof (Console).GetMethod("WriteLine", new[] {typeof (string)}));
        method.DynamicInvoke("Hello world");
    }

    static Delegate CreateDelegate(MethodInfo method)
    {
        if (method == null)
        {
            throw new ArgumentNullException("method");
        }

        if (!method.IsStatic)
        {
            throw new ArgumentNullException("method", "The provided method is not static.");
        }

        if (method.ContainsGenericParameters)
        {
            throw new ArgumentException("The provided method contains unassigned generic type parameters.");
        }

        return method.CreateDelegate(typeof(Delegate)); // This does not work: System.ArgumentException: Type must derive from Delegate.
    }
}

I hoped that the MethodInfo.CreateDelegatemethod could figure out the correct delegate type itself. Well, obviously it cannot. So, how do I create an instance of System.Typerepresenting a delegate with a signature matching the provided MethodInfoinstance?

我希望该MethodInfo.CreateDelegate方法可以自己找出正确的委托类型。嗯,显然不能。那么,如何创建一个System.Type代表具有与提供的MethodInfo实例匹配的签名的委托的实例?

采纳答案by Oksana Gimmel

You can use System.Linq.Expressions.Expression.GetDelegateTypemethod:

您可以使用System.Linq.Expressions.Expression.GetDelegateType方法:

using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

class Program
{
    static void Main()
    {
        var writeLine = CreateDelegate(typeof(Console).GetMethod("WriteLine", new[] { typeof(string) }));
        writeLine.DynamicInvoke("Hello world");

        var readLine = CreateDelegate(typeof(Console).GetMethod("ReadLine", Type.EmptyTypes));
        writeLine.DynamicInvoke(readLine.DynamicInvoke());
    }

    static Delegate CreateDelegate(MethodInfo method)
    {
        if (method == null)
        {
            throw new ArgumentNullException("method");
        }

        if (!method.IsStatic)
        {
            throw new ArgumentException("The provided method must be static.", "method");
        }

        if (method.IsGenericMethod)
        {
            throw new ArgumentException("The provided method must not be generic.", "method");
        }

        return method.CreateDelegate(Expression.GetDelegateType(
            (from parameter in method.GetParameters() select parameter.ParameterType)
            .Concat(new[] { method.ReturnType })
            .ToArray()));
    }
}

There is probably a copy-paste error in the 2nd check for !method.IsStatic- you shouldn't use ArgumentNullExceptionthere. And it is a good style to provide a parameter name as an argument to ArgumentException.

在第二次检查中可能存在复制粘贴错误!method.IsStatic- 您不应该ArgumentNullException在那里使用。提供参数名称作为ArgumentException.

Use method.IsGenericMethodif you want to reject all generic methods and method.ContainsGenericParametersif you want to reject only generic methods having unsubstituted type parameters.

使用method.IsGenericMethod,如果你想拒绝所有通用的方法和method.ContainsGenericParameters如果您想拒绝无取代类型参数仅泛型方法。

回答by Khoa Nguyen

You may want to try System.LinQ.Expressions

您可能想尝试 System.LinQ.Expressions

...
using System.Linq.Expressions;
...

static Delegate CreateMethod(MethodInfo method)
{
    if (method == null)
    {
        throw new ArgumentNullException("method");
    }

    if (!method.IsStatic)
    {
        throw new ArgumentException("The provided method must be static.", "method");
    }

    if (method.IsGenericMethod)
    {
        throw new ArgumentException("The provided method must not be generic.", "method");
    }

    var parameters = method.GetParameters()
                           .Select(p => Expression.Parameter(p.ParameterType, p.Name))
                           .ToArray();
    var call = Expression.Call(null, method, parameters);
    return Expression.Lambda(call, parameters).Compile();
}

and use it later as following

并在以后使用它如下

var method = CreateMethod(typeof (Console).GetMethod("WriteLine", new[] {typeof (string)}));
method.DynamicInvoke("Test Test");