如何从Action 获取方法的自定义属性?
如何从Action
委托中获取方法的自定义属性?
例:
//simple custom attribute public class StatusAttribute : Attribute { public string Message { get; set; } = string.Empty; } // an extension methodto wrap MethodInfo.GetCustomAttributes(Type, Bool) with // generics for the custom Attribute type public static class MethodInfoExtentions { public static IEnumerable GetCustomAttributes(this MethodInfo methodInfo, bool inherit) where TAttribute : Attribute { object[] attributeObjects = methodInfo.GetCustomAttributes(typeof(TAttribute), inherit); return attributeObjects.Cast(); } } // test class with a test method to implment the custom attribute public class Foo { [Status(Message="I'm doing something")] public void DoSomething() { // code would go here } } // creates an action and attempts to get the attribute on the action private void CallDoSomething() { Action myAction = new Action(m => m.DoSomething()); IEnumerable statusAttributes = myAction.Method.GetCustomAttributes(true); // Status Attributes count = 0? Why? }
我意识到我可以通过在Foo上使用reflection来做到这一点,但是对于我想要创建的东西,我必须使用Action
。
问题是该动作并不直接指向Foo.DoSomething
。 它指向编译器生成的表单方法:
private static void <>__a(Foo m) { m.DoSomething(); }
这里的一个选项是将其更改为Expression
,然后您可以解剖表达式树并提取属性:
Expression> myAction = m => m.DoSomething(); var method = ((MethodCallExpression)myAction.Body).Method; var statusAttributes = method.GetCustomAttributes(true); int count = statusAttributes.Count(); // = 1
问题是lambda m => m.DoSomething()
与DoSomething
。 它是一个lambda表达式,它被编译成编译器生成的方法上的方法调用,可能使用编译器生成的类型(尽管可能不是后者,因为没有捕获的局部变量)。
从Foo
类型的实例(非静态)方法获取Action
一种非常详细的方法是:
var myAction = (Action)Delegate.CreateDelegate( typeof(Action ), null, // treat method as static, even though it's not typeof(Foo).GetMethod("DoSomething", BindingFlags.Instance | BindingFlags.Public) );
显然,这远非理想,在你的情况下可能实际上毫无用处 ; 但值得了解;)
更新 :实际上,我刚刚想到你可以编写一个快速扩展方法,使你想要包装为静态方法的任何实例方法都很容易(并维护“正确的” MethodInfo
):
public static class ActionEx { public static Action ToStaticMethod (this Action action) { if (!(action.Target is T)) { throw new ArgumentException("Blah blah blah."); } return (Action )Delegate.CreateDelegate( typeof(Action ), null, action.Method ); } }
这将允许您这样做:
Action myAction = new Action(new Foo().DoSomething).ToStaticMethod ();
不可否认,它不如m => m.DoSomething()
; 但它确实为您提供了Action
其Method
属性实际上直接引用了DoSomething
方法。
或者,您可以使用Expression
而不是Action
,并从中获取MethodInfo
。 请注意,在这种情况下语法看起来是一样的:
Action myAction = m => m.DoSomething(); Expression> myExpression = m => m.DoSomething();
但这是一个棘手的命题,因为任意Expression
不能保证像m => m.DoSomething()
一样简单。
以前的答案都没有(除了没有用户代码的@Marc Gravell♦)似乎是可编译的:)
所以我建议我的:
private static void CallDoSomething() { var f = new Foo(); Action myAction = f.DoSomething; IEnumerable statusAttributes = myAction.Method.GetCustomAttributes (true); }