How to get custom method attributes from Action <T>?

How to get custom method attributes from Action<T> ?

Example:

 //simple custom attribute public class StatusAttribute : Attribute { public StatusAttribute() { Message = ""; } public string Message { get; set; } } // an extension methodto wrap MethodInfo.GetCustomAttributes(Type, Bool) with // generics for the custom Attribute type public static class MethodInfoExtentions { public static IEnumerable<TAttribute> GetCustomAttributes<TAttribute>(this MethodInfo methodInfo, bool inherit) where TAttribute : Attribute { object[] attributeObjects = methodInfo.GetCustomAttributes(typeof(TAttribute), inherit); return attributeObjects.Cast<TAttribute>(); } } // 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<Foo> myAction = new Action<Foo>(m => m.DoSomething()); IEnumerable<StatusAttribute> statusAttributes = myAction.Method.GetCustomAttributes<StatusAttribute>(true); // Status Attributes count = 0? Why? } 

I understand that I can do this using reflection in Foo, but for what I'm trying to create, I have to use Action<T> .

+7
source share
3 answers

The problem is that the action does not directly point to Foo.DoSomething - it points to the method generated by the form compiler:

 private static void <>__a(Foo m) { m.DoSomething(); } 

One option is to change it to Expression<Action<T>> , after which you can parse the expression tree and extract the attributes:

  Expression<Action<Foo>> myAction = m => m.DoSomething(); var method = ((MethodCallExpression)myAction.Body).Method; var statusAttributes = method.GetCustomAttributes<StatusAttribute>(true); int count = statusAttributes.Count(); // = 1 
+10
source

The problem is that lambda m => m.DoSomething() does not match DoSomething . This is a lambda expression that compiles into a method call on a compiler-generated method, possibly using the type generated by the compiler (although it may not be the last, since there are no captured local variables).

A very complicated way to get an Action<Foo> from an instance of a (non-static) method of type Foo :

 var myAction = (Action<Foo>)Delegate.CreateDelegate( typeof(Action<Foo>), null, // treat method as static, even though it not typeof(Foo).GetMethod("DoSomething", BindingFlags.Instance | BindingFlags.Public) ); 

Obviously, this is far from ideal and probably practically useless in your case; but it is worth knowing;)


Refresh . Actually, it just occurred to me that you could write a quick extension method to make it simple for any instance method that you want to wrap as a static method (and keep the "correct" MethodInfo ):

 public static class ActionEx { public static Action<T> ToStaticMethod<T>(this Action action) { if (!(action.Target is T)) { throw new ArgumentException("Blah blah blah."); } return (Action<T>)Delegate.CreateDelegate( typeof(Action<T>), null, action.Method ); } } 

This will allow you to do:

 Action<Foo> myAction = new Action(new Foo().DoSomething).ToStaticMethod<Foo>(); 

Admittedly, this is not as good as m => m.DoSomething() ; but it gives you an Action<T> , the Method property actually refers to the DoSomething method.


Alternatively, instead of Action<T> you can use Expression<Action<T>> and get MethodInfo from this. Note that the syntax looks the same in this case:

 Action<Foo> myAction = m => m.DoSomething(); Expression<Action<Foo>> myExpression = m => m.DoSomething(); 

But this is a complex proposition, since an arbitrary Expression<Action<T>> not guaranteed as simple as m => m.DoSomething() .

+3
source

None of the previous answers (except Marc, which has no user code) seems to be compiling :)

So, I would suggest mine:

  private static void CallDoSomething() { var f = new Foo(); Action myAction = f.DoSomething; IEnumerable<StatusAttribute> statusAttributes = myAction.Method.GetCustomAttributes<StatusAttribute>(true); } 
0
source

All Articles