2009-10-06 7 views
3

La question que j'ai est la suivante: Si j'ai l'objet MethodInfo, pour une méthode, obtenu à partir d'un type d'interface, et j'ai aussi l'objet Type pour une classe qui implémente cette interface, mais implémente la méthode implémentation, comment obtenir correctement l'objet MethodInfo correspondant pour la méthode d'implémentation dans cette classe? La raison pour laquelle je dois faire cela est que les méthodes d'implémentation peuvent avoir des attributs qui leur sont appliqués, et j'ai besoin de les trouver par réflexion, mais la classe qui doit trouver ces attributs n'a qu'une référence d'objet pour la classe d'implémentation et l'objet Type (+ objets MethodInfo correspondants) pour l'interface.Traduction d'un objet MethodInfo obtenu à partir d'un type d'interface vers l'objet MethodInfo correspondant sur un type d'implémentation en C#?

Ainsi, supposons que je le programme suivant:

using System; 
using System.Reflection; 

namespace ConsoleApplication8 
{ 
    public interface ITest 
    { 
     void Test(); 
    } 

    public class Test : ITest 
    { 
     void ITest.Test() 
     { 
      throw new NotImplementedException(); 
     } 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      Type interfaceType = typeof(ITest); 
      Type classType = typeof(Test); 

      MethodInfo testMethodViaInterface = 
       interfaceType.GetMethods()[0]; 
      MethodInfo implementingMethod = 
       classType.GetMethod(/* ??? */"Test"); 

      Console.Out.WriteLine("interface: " + 
       testMethodViaInterface.Name); 
      if (implementingMethod != null) 
       Console.Out.WriteLine("class: " + 
        implementingMethod.Name); 
      else 
       Console.Out.WriteLine("class: unable to locate"); 

      Console.Out.Write("Press enter to exit..."); 
      Console.In.ReadLine(); 
     } 
    } 
} 

Courir cela me donne:

interface: Test 
class: unable to locate 
Press enter to exit... 

Up dans le code il y a un appel .GetMethod avec un ??? commentaire. Cette partie est ce que j'ai besoin d'aide. Soit ce que j'ai besoin de spécifier ici (et j'ai beaucoup testé, ce qui m'amène à l'inverse) ou ce dont j'ai besoin pour remplacer ce code.

Depuis que j'ai utilisé l'implémentation explicite de la méthode à partir de l'interface, le nom réel de la méthode n'est pas seulement "Test". Si je vide le contenu des array GetMethods() du type de classe, avec ce code:

foreach (var mi in classType.GetMethods(
    BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)) 
{ 
    Console.Out.WriteLine(mi.Name); 
} 

puis-je obtenir ceci:

ConsoleApplication8.ITest.Test   <-- this is the one I want 
ToString 
Equals 
GetHashCode 
GetType 
Finalize 
MemberwiseClone 

clairement, le nom a le nom complet de la interface et son espace de noms en face de lui. Cependant, en raison de la surcharge, il semble que je doive trouver toutes ces méthodes d'implémentation dans la classe (c'est-à-dire en supposant que plusieurs méthodes de test varient en fonction des paramètres), puis comparer les paramètres.

Existe-t-il un moyen plus simple? Fondamentalement, je voudrais, une fois que j'ai l'objet MethodInfo pour une méthode d'une interface, trouver la méthode exacte qu'une classe qui implémente cette méthode, en obtenant son objet MethodInfo. Notez que je suis dans une situation de boucle ici, donc si je dois parcourir les méthodes de la classe pour trouver la méthode exacte de l'interface, c'est ok, tant que j'ai un bon moyen d'identifier quand J'ai trouvé le bon.

J'ai essayé de changer la boucle au-dessus comme ceci:

foreach (var mi in classType.GetMethods(
    BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)) 
{ 
    if (mi.GetBaseDefinition() == testMethodViaInterface) 
     Console.Out.WriteLine(mi.Name); 
} 

Cela n'a pas imprimer quoi que ce soit, si clairement GetBaseDefinition sur une telle méthode ne pointe pas à l'objet MethodInfo de l'interface.

Des pointeurs?

+0

Il y a une bonne solution à ce problème ici: http://stackoverflow.com/questions/1113635/how-to-get-methodinfo-of-interface-method-having-implementing-methodinfo -of-cla – gillyb

Répondre

5

Regardez Type.GetInterfaceMap. Désolé - je suis pressé donc je n'ai pas le temps pour une réponse complète mais ça devrait être un début.

+0

Ok, laissez-moi faire ça. –

+0

Ooh, c'était exactement ce dont j'avais besoin, je veux construire une méthode d'extension par-dessus pour faciliter l'interrogation, mais ça a marché! –

+0

Je posterai une réponse de mon choix avec la méthode d'extension et le code édité. –

10

Pour référence future, et si d'autres sont intéressés, la solution qui m'a été donnée par @Greg Beechhere devait utiliser Type.GetInterfaceMap.

Voici le code de programme modifié avec une méthode d'extension en bas.

using System; 
using System.Linq; 
using System.Reflection; 
using System.Diagnostics; 

namespace ConsoleApplication8 
{ 
    public interface ITest 
    { 
     void Test(); 
    } 

    public class Test : ITest 
    { 
     void ITest.Test() 
     { 
      throw new NotImplementedException(); 
     } 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      Type interfaceType = typeof(ITest); 
      Type classType = typeof(Test); 

      InterfaceMapping map = classType.GetInterfaceMap(interfaceType); 

      MethodInfo testMethodViaInterface = interfaceType.GetMethods()[0]; 
      MethodInfo implementingMethod = testMethodViaInterface.GetImplementingMethod(classType); 

      Console.Out.WriteLine("interface: " + testMethodViaInterface.Name); 
      if (implementingMethod != null) 
       Console.Out.WriteLine("class: " + implementingMethod.Name); 
      else 
       Console.Out.WriteLine("class: unable to locate"); 

      Console.Out.Write("Press enter to exit..."); 
      Console.In.ReadLine(); 
     } 
    } 

    public static class TypeExtensions 
    { 
     /// <summary> 
     /// Gets the corresponding <see cref="MethodInfo"/> object for 
     /// the method in a class that implements a specific method 
     /// from an interface. 
     /// </summary> 
     /// <param name="interfaceMethod"> 
     /// The <see cref="MethodInfo"/> for the method to locate the 
     /// implementation of.</param> 
     /// <param name="classType"> 
     /// The <see cref="Type"/> of the class to find the implementing 
     /// method for. 
     /// </param> 
     /// <returns> 
     /// The <see cref="MethodInfo"/> of the method that implements 
     /// <paramref name="interfaceMethod"/>. 
     /// </returns> 
     /// <exception cref="ArgumentNullException"> 
     /// <para><paramref name="interfaceMethod"/> is <c>null</c>.</para> 
     /// <para>- or -</para> 
     /// <para><paramref name="classType"/> is <c>null</c>.</para> 
     /// </exception> 
     /// <exception cref="ArgumentException"> 
     /// <para><paramref name="interfaceMethod"/> is not defined in an interface.</para> 
     /// </exception> 
     public static MethodInfo GetImplementingMethod(this MethodInfo interfaceMethod, Type classType) 
     { 
      #region Parameter Validation 

      if (Object.ReferenceEquals(null, interfaceMethod)) 
       throw new ArgumentNullException("interfaceMethod"); 
      if (Object.ReferenceEquals(null, classType)) 
       throw new ArgumentNullException("classType"); 
      if (!interfaceMethod.DeclaringType.IsInterface) 
       throw new ArgumentException("interfaceMethod", "interfaceMethod is not defined by an interface"); 

      #endregion 

      InterfaceMapping map = classType.GetInterfaceMap(interfaceMethod.DeclaringType); 
      MethodInfo result = null; 

      for (Int32 index = 0; index < map.InterfaceMethods.Length; index++) 
      { 
       if (map.InterfaceMethods[index] == interfaceMethod) 
        result = map.TargetMethods[index]; 
      } 

      Debug.Assert(result != null, "Unable to locate MethodInfo for implementing method"); 

      return result; 
     } 
    } 
}