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

yacmzcpb  于 2022-11-19  发布在  .NET
关注(0)|答案(3)|浏览(167)

我需要一个方法,该方法接受一个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.
    }
}

我希望MethodInfo.CreateDelegate方法本身能够找出正确的委托类型。很明显,它不能。那么,我如何创建System.Type的一个示例来表示一个具有与所提供的MethodInfo示例相匹配的签名的委托呢?

rsaldnfx

rsaldnfx1#

可以使用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

iq0todco

iq0todco2#

您可能想试试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();
}

并在以后按如下方式使用

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

vnjpjtjt3#

如果要创建非静态方法,必须实现目标/示例化对象。

/// <summary>
/// Create delegate by methodinfo in target
/// </summary>
/// <param name="method">method info</param>
/// <param name="target">A instance of the object which contains the method where will be execute</param>
/// <returns>delegate or null</returns>
public static Delegate? CreateDelegateWithTarget(MethodInfo? method, object? target)
{
    if (method is null ||
        target is null)
        return null;

    if (method.IsStatic)
        return null;

    if (method.IsGenericMethod)
        return null;

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

相关问题