行动代表.如何在委托中调用方法信息?

Joa*_*nna 8 c# delegates

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

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

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

    Foo(() =>
    {
            instanceOfFooClass.Method1().Method2();
    });
Run Code Online (Sandbox Code Playgroud)

在Foo方法中,我想确保Method1和Method2具有MyCustomAttribute.但是action.Method给了我MethodInfo,这是委托的动作,当使用lambda表达式时会发生.有没有办法获得Method1和Method2 MethodInfo?

Dav*_*yon 5

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

有了Expression<T>你可以很容易地访问这样的方法信息:

public MethodInfo GetMethodInfo(Expression<Action> action)
{
    return ((MethodCallExpression)action.Body).Method;
}
Run Code Online (Sandbox Code Playgroud)

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

private void InvokeMethod(Expression<Action> action)
{
    action.Compile().Invoke();
}
Run Code Online (Sandbox Code Playgroud)

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

var methodInfo = ((MethodCallExpression)myAction.Body).Method;
var attributes = methodInfo.GetCustomAttributes<T>(true);
Run Code Online (Sandbox Code Playgroud)

示例 以下示例显示将链式方法调用传递给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");
    }
}
Run Code Online (Sandbox Code Playgroud)