2011-01-27 5 views
7

Bir yöntemin özel özniteliklerini Action<T>'dan nasıl edinebilirim?Bir yöntemin özel niteliklerini Action <T>'dan nasıl edinebilirim?

Örnek:

//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? 
} 

ben Foo üzerinde yansıma kullanarak bu yapabilirdi farkındayım ama oluşturmaya çalışıyorum ne için ben bir Action<T> kullanmak zorunda.

cevap

10

sorun - işlemi direkt olarak Foo.DoSomething işaret etmez - formun bir derleyici tarafından oluşturulan yöntem işaret:

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

bir seçenek burada daha sonra, bir Expression<Action<T>> olarak değiştirmek için olacaktır Eğer sonradan ifade ağacı teşrih ve özelliklerini çıkarabilir:

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

konu lambda m => m.DoSomething()değilDoSomething aynı olmasıdır. Derleyici tarafından oluşturulan bir yöntemde, muhtemelen bir derleyici tarafından oluşturulan bir yöntem kullanılarak (yakalanan yerel değişkenler olmadığından belki de ikincisini değil) bir yöntem çağrısına derlenen bir lambda ifadesidir.

Foo türün örneği (statik olmayan) yöntemi kullanırken bir Action<Foo> almanın çok ayrıntılı bir yol şudur:

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

, o çok idealdir ve muhtemelen aslında yararsız yılında senin durumun; Eğer Statik yöntem olarak sarmak istiyorum herhangi örnek yöntemi için kolaylaştıracağım için hızlı bir uzantısı yöntem yazabilirsiniz Aslında, sadece aklıma geldi:


) Güncelleme; ama bilerek değer (ve MethodInfo "doğru" korumak):

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 
     ); 
    } 
} 

Bu size yapmanızı sağlayacaktır olacaktır:

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

Kuşkusuz, m => m.DoSomething() kadar güzel değil; Ancak ,, Method özelliğinin DoSomething yöntemine doğrudan başvurduğu bir Action<T> sağlar. yerine Action<T> ait


Alternatif olarak,, bir Expression<Action<T>> kullanmak ve bundan MethodInfo alabilir.

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

Ama keyfi bir Expression<Action<T>> sadece m => m.DoSomething() kadar basit garanti edilmez beri zor bir öneri geçerli: sözdizimi, bu durumda sadece aynı görünüyor unutmayın.(Marc hayır kullanıcının kodu vardır ki hariç) önceki cevapların

+0

ama Bu etkileyici bir uzantısı yöntemidir. – mbursill

0

Yok derlenebilir :)

Yani benim önereceğini gibi görünüyor: Ben temizleyici sözdizimi yoluna devam etmesini tercih

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

Haklısınız; Benimki bir aptal hatası vardı. Sonuç çok çirkin olsa da, onu "sabitledim". –

İlgili konular