2009-08-04 7 views
2

Je voudrais obtenir le nom de la méthode qui est déléguée en tant que Func.Récupérer le nom de la méthode invoquée exécutée dans un Func

Func<MyObject, object> func = x => x.DoSomeMethod(); 
string name = ExtractMethodName(func); // should equal "DoSomeMethod" 

Comment puis-je y parvenir?

- Pour les droits de vantardise -

Faire ExtractMethodName travaille aussi avec une invocation de la propriété, l'avoir retourne le nom de la propriété dans ce cas.

par ex.

Func<MyObject, object> func = x => x.Property; 
string name = ExtractMethodName(func); // should equal "Property" 

Répondre

11

Regardez Ma! Pas d'arbres d'expression!

Voici une version rapide, sale et spécifique à l'implémentation qui récupère le jeton de métadonnées du flux IL du lambda sous-jacent et le résout.

private static string ExtractMethodName(Func<MyObject, object> func) 
{ 
    var il = func.Method.GetMethodBody().GetILAsByteArray(); 

    // first byte is ldarg.0 
    // second byte is callvirt 
    // next four bytes are the MethodDef token 
    var mdToken = (il[5] << 24) | (il[4] << 16) | (il[3] << 8) | il[2]; 
    var innerMethod = func.Method.Module.ResolveMethod(mdToken); 

    // Check to see if this is a property getter and grab property if it is... 
    if (innerMethod.IsSpecialName && innerMethod.Name.StartsWith("get_")) 
    { 
     var prop = (from p in innerMethod.DeclaringType.GetProperties() 
        where p.GetGetMethod() == innerMethod 
        select p).FirstOrDefault(); 
     if (prop != null) 
      return prop.Name; 
    } 

    return innerMethod.Name; 
} 
+0

Merci! Je ne m'attendais pas à ce que les choses soient aussi géniales mais ça fonctionne comme je le souhaite. – berko

+1

Que faire si la méthode est dans un module différent? Ne devriez-vous pas obtenir le module du paramètre de la fonction? – SLaks

0

Je ne pense pas que cela soit possible dans le cas général. Et si vous aviez:

Func<MyObject, object> func = x => x.DoSomeMethod(x.DoSomeOtherMethod()); 

Qu'attendez-vous? Ceci étant dit, vous pouvez utiliser la réflexion pour ouvrir l'objet Func et voir ce qu'il fait à l'intérieur, mais vous ne pourrez le résoudre que dans certains cas.

+0

Étant donné ce que vous avez, je voudrais que la réponse soit "DoSomeMethod". Est-il possible que l'exemple de propriété que j'ai fourni soit en fait plus facile parce que cela limiterait la complexité potentielle de l'interrogation Func? – berko

0

Vérifiez ma réponse hack ici:

Why is there not a `fieldof` or `methodof` operator in C#?

Dans le passé, je l'ai fait une autre façon qui a utilisé Func au lieu de Expression<Func<...>>, mais j'étais beaucoup moins satisfait du résultat. Le MemberExpression utilisé pour détecter le champ dans ma méthode fieldof renvoie un PropertyInfo lorsqu'une propriété est utilisée.

Edit # 1: Cela fonctionne pour un sous-ensemble du problème:

Func<object> func = x.DoSomething; 
string name = func.Method.Name; 

Edit # 2: Celui qui m'a marqué vers le bas devrait prendre une seconde pour réaliser ce qui se passe ici. Les arbres d'expression peuvent être implicitement utilisés avec des expressions lambda et constituent le moyen le plus rapide et le plus fiable d'obtenir les informations demandées spécifiques ici.