c# - 当无法事先知道方法签名时,如何从 MethodInfo 创建委托(delegate)?

标签 c# .net reflection delegates methodinfo

我需要一个方法,它采用一个 MethodInfo 实例来表示具有任意签名的非泛型静态方法,并返回一个绑定(bind)到该方法的委托(delegate),该委托(delegate)稍后可以使用 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.
    }
}

我希望 MethodInfo.CreateDelegate 方法可以自己找出正确的委托(delegate)类型。好吧,显然不能。那么,如何创建一个 System.Type 实例来表示一个签名与所提供的 MethodInfo 实例相匹配的委托(delegate)?

最佳答案

您可以使用 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()));
    }
}

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

如果您想拒绝所有泛型方法,请使用 method.IsGenericMethod;如果您只想拒绝具有未替换类型参数的泛型方法,请使用 method.ContainsGenericParameters

关于c# - 当无法事先知道方法签名时,如何从 MethodInfo 创建委托(delegate)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16364198/

相关文章:

c# - LINQ 中的高效列表 self 比较?

c# - 在 C# 中交换两个列表

c# - 为什么不能在 .Net 的静态方法中使用关键字 'this'?

c# - 更改 WCF 引用 URL .Net Core

c# - 使用反射实例化一个实现通用接口(interface)的类

c# - 我可以从一个字符串开始并实例化该字符串的对象吗?

c# - MVC 模拟 (Moq) - HttpContext.Current.Server.MapPath

c# - Lambda 表达式和 InvokeOperation

c# - 获取 lambda 表达式的 MethodInfo

reflection - 获取参数名称