操作委托.如何获取在委托中调用的方法信息

本文关键字:调用 信息 方法 获取 何获取 操作 | 更新日期: 2023-09-27 18:36:20

我需要获取在操作委托中调用的方法的 MethodInfo 以检查在操作中调用的方法是否具有 MyCustomAttibute

    public void Foo( Action action )
    {
        if(Attribute.GetCustomAttributes(action.Method, typeof(MyCustomAttribute)).Count() == 0)
        {
            throw new ArgumentException("Invalid action");
        }
    }

Foo方法应该能够按如下方式调用:

    Foo(() =>
    {
            instanceOfFooClass.Method1().Method2();
    });

在Foo方法中,我想确保方法1和方法2具有MyCustomAttribute。然而行动。方法给了我 MethodInfo,这是委托的操作,在使用 lambda 表达式时发生。有没有办法获取方法1和方法2方法信息?

操作委托.如何获取在委托中调用的方法信息

正如评论中提到的,Expression<T>可能是实现这一目标的最佳方法。 但是,它需要在运行时进行Compile(),因此应对其进行性能分析。

使用Expression<T>您可以轻松访问方法信息,如下所示:

public MethodInfo GetMethodInfo(Expression<Action> action)
{
    return ((MethodCallExpression)action.Body).Method;
}

但是,在执行操作之前,您必须执行以下操作:

private void InvokeMethod(Expression<Action> action)
{
    action.Compile().Invoke();
}

编辑啊,是的,我忘记了如何访问客户属性。 你会这样做:

var methodInfo = ((MethodCallExpression)myAction.Body).Method;
var attributes = methodInfo.GetCustomAttributes<T>(true);

下面是一个示例,显示将链式方法调用传递给Expression<Action>

public class ActionTest
{
    public void DoAction(Action action)
    {
        action();
    }
    public void DoExpressionAction(Expression<Action> action)
    {
        var method2Info = ((MethodCallExpression)action.Body).Method;
        // a little recursion needed here
        var method1Info = ((MethodCallExpression)((MethodCallExpression)action.Body).Object).Method;
        var myattributes2 = method2Info.GetCustomAttributes(typeof(MyAttribute), true);
        var myattributes1 = method1Info.GetCustomAttributes(typeof(MyAttribute), true);
        action.Compile().Invoke();
    }
}
[AttributeUsage(AttributeTargets.Method)]
public class MyAttribute : Attribute
{
    private string message;
    public MyAttribute(string message)
    {
        this.message = message;
    }
}
public class MethodTest
{
    [MyAttribute("Number1")]
    public MethodTest Method1()
    {
        Console.WriteLine("Action");
        return this;
    }
    [MyAttribute("Number2")]
    public MethodTest Method2()
    {
        Console.WriteLine("ExpressionAction");
        return this;
    }
}

class Program
{
    static void Main(string[] args)
    {
        ActionTest target = new ActionTest();
        MethodTest instance = new MethodTest();
        target.DoExpressionAction(() => instance.Method1().Method2() );
        Console.ReadLine();
    }
    static void Method1()
    {
        Console.WriteLine("Action");
    }
    static void Method2()
    {
        Console.WriteLine("ExpressionAction");
    }
}

如果你这样称呼你的Foo() methdod:

Foo(instanceOfFooClass.Method);

您的代码按预期工作(毕竟 void 方法是操作)。附带说明一下,我认为"链接"方法调用实际上很重要,因为您只传递最后一个方法调用。

演示行为的完整示例:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication4
{
    class MyCustomAttribute : Attribute { }
    class FooClass
    {
        [MyCustom]
        public void DecoratedMethod() { Console.WriteLine("Decorated Method - executed."); }
        public void NotDecoratedMethod() { Console.WriteLine("Not Decoreated Method - executed."); }
    }
    class Program
    {
        static void Main(string[] args)
        {
            FooClass instanceOfFooClass = new FooClass();
            Foo(instanceOfFooClass.DecoratedMethod);
            Foo(instanceOfFooClass.NotDecoratedMethod);
            Console.ReadLine();
        }
        public static void Foo(Action action)
        {
            if (Attribute.GetCustomAttributes(action.Method, typeof(MyCustomAttribute)).Count() == 0)
                Console.WriteLine(string.Format("Invalid method {0}", action.Method.Name));
            else
            {
                Console.WriteLine(string.Format("Valid method {0}", action.Method.Name));
                action.Invoke();
            }
        }
    }
}