如何从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() ; 但它确实为您提供了ActionMethod属性实际上直接引用了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); }