我需要为Action委托中调用的方法获取MethodInfo,以便检查Action中调用的方法是否具有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方法中,我想确保Method1和Method2具有MyCustomAttribute。但是action.Method给了我MethodInfo,这是委托的动作,当使用lambda表达式时会发生。有没有办法获得Method1和Method2 MethodInfo?
答案 0 :(得分:5)
正如评论中所提到的,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");
}
}
答案 1 :(得分:4)
如果你这样称呼Foo()
方法:
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();
}
}
}
}