2010-07-23 8 views
7

J'ai un MethodInfo passé pour une fonction et je veux faire ce qui suitComment puis-je déterminer si une méthode est une instance générique d'une méthode générique

MethodInfo containsMethod = typeof(ICollection<>).GetMethod("Contains"); 
if (methodInfo.Equals(containsMethod) 
{ 
    // do something 
} 

Mais cela ne fonctionne pas parce que le METHODINFO a un type générique spécifique. Car l'exemple fonctionne si je savais que ICollection était toujours de type string.

MethodInfo containsMethod = typeof(ICollection<string>).GetMethod("Contains"); 
if (methodInfo.Equals(containsMethod) 
{ 
    // do something 
} 

Comment puis-je vérifier si le MethodInfo est une dactylographiées toute instance de la méthode générique sans se soucier de ce type est?

Merci.

EDIT: Question clarification

Comme l'a souligné à juste titre la méthode n'est pas générique, mais la classe contenant est si la question est plus comment je savoir si le MethodInfo est pour un type qui est une instance typée de ICollection <>.

EDIT: contexte plus

Je suis en train d'écrire un fournisseur LINQ et essayer de gérer le « dans » cas

IList<string> myList = new List<string>{ "1", "2" }; 

from Something s in ... 
where myList.Contains(s.name) 
select s; 

Répondre

3

Vous pouvez vérifier le type déclarant:

if(methodInfo.Name == "Contains" 
    && methodInfo.DeclaringType.IsGenericType 
    && methodInfo.DeclaringType.GetGenericTypeDefinition() == typeof(ICollection<>)) 
{ 
+0

OMI le plus simple et le plus clair, merci. –

4

Notez que ICollection<T>.Contains est pas une méthode générique - il est un non -generic méthode d'un type générique. Autrement IsGenericMethod et GetGenericTypeDefinition aideraient. Vous pouvez obtenir la définition de type générique (DeclaringType.GetGenericTypeDefinition()) et remonter jusqu'à Contains, mais je me demande si vous abordez ce problème à la dure.

Habituellement, si vous utilisez la réflexion, il peut être pragmatique de tomber à IList non générique - à moins que vous besoin les données de type (par exemple, pour la méta-programmation). Et dans ce cas, je regarderais attentivement pour voir si vous pouvez simplifier la configuration ici.

+0

Merci pour la réponse.Ajout d'un contexte ci-dessus pour ce que j'essaie d'accomplir. L'approche DeclaringType semble prometteuse, je vais essayer et revenir. –

0

Le problème est que vous n'avez pas de méthode générique: vous avez une méthode non générique sur un type générique. Je ne connais pas de moyen d'utiliser la réflexion pour passer directement d'une définition de méthode sur un type générique ouvert à cette même méthode sur un type générique fermé ou vice versa. Cependant, vous pouvez profiter du fait que les méthodes retournées par GetMethods() sur les types génériques ouverts et fermés devrait toujours être dans le même ordre et faire la traduction par index:

MethodInfo containsMethod = typeof(ICollection<>).GetMethod("Contains"); 
var methodIndex = Array.IndexOf(methodInfo.DeclaringType.GetMethods(), methodInfo); 
var methodOnTypeDefinition = methodInfo.DeclaringType.GetGenericTypeDefinition().GetMethods()[methodIndex]; 
if (methodOnTypeDefinition.Equals(containsMethod)) 
{ 
    // do something 
} 
2

Une vérification d'erreur devrait être ajoutée à cela, mais je crois que cela fait à peu près ce que vous voulez. Vous pouvez utiliser une méthode avec ou sans argument de type en tant que paramètre.

static bool IsContainsMethod(MethodInfo methodInfo) 
{ 
    Type[] types = { methodInfo.GetParameters().First().ParameterType }; 
    MethodInfo containsMethod = typeof(ICollection<>).MakeGenericType(types).GetMethod("Contains"); 
    return methodInfo.Equals(containsMethod); 
} 
0

essayer cette méthode

public static bool CheckGenericMethod(MethodInfo methodInfo) 
    { 
     bool areSimilarMethods = false; 
     MethodInfo methodToCompare = typeof(ISomeInterface<>).GetMethod("func"); 
     Type interfaceInfo = methodInfo.DeclaringType.GetInterface(methodToCompare.DeclaringType.FullName); 

     if (interfaceInfo != null) 
      areSimilarMethods = (methodToCompare.Name.Equals(methodInfo.Name) 
      && interfaceInfo.FullName.Contains(methodToCompare.DeclaringType.FullName)); 
     else 
     { 
      areSimilarMethods = methodToCompare.DeclaringType.Equals(methodInfo.DeclaringType); 
     } 

     return areSimilarMethods; 

    } 

et est ici l'exemple d'utilisation complète.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Reflection; 

namespace TestReflection 
{ 
    public class Program 
    { 
     static void Main(string[] args) 
     { 
      MethodInfo info1 = typeof(ISomeInterface<>).GetMethod("func"); 
      MethodInfo info2 = typeof(MyStringCollection).GetMethod("func"); 
      MethodInfo info3 = typeof(MyProgramCollection).GetMethod("func"); 
      MethodInfo info4 = typeof(MyXCollection).GetMethod("func"); 

      if (CheckGenericMethod(info1)) Console.WriteLine("true");else Console.WriteLine("false"); 
      if (CheckGenericMethod(info2)) Console.WriteLine("true");else Console.WriteLine("false"); 
      if (CheckGenericMethod(info3)) Console.WriteLine("true");else Console.WriteLine("false"); 
      if (CheckGenericMethod(info4)) Console.WriteLine("true"); else Console.WriteLine("false"); 

      Console.ReadKey(); 
     } 


     public static bool CheckGenericMethod(MethodInfo methodInfo) 
     { 
      bool areSimilarMethods = false; 
      MethodInfo methodToCompare = typeof(ISomeInterface<>).GetMethod("func"); 
      Type interfaceInfo = methodInfo.DeclaringType.GetInterface(methodToCompare.DeclaringType.FullName); 

      if (interfaceInfo != null) 
       areSimilarMethods = (methodToCompare.Name.Equals(methodInfo.Name) 
       && interfaceInfo.FullName.Contains(methodToCompare.DeclaringType.FullName)); 
      else 
      { 
       areSimilarMethods = methodToCompare.DeclaringType.Equals(methodInfo.DeclaringType); 
      } 

      return areSimilarMethods; 

     } 
    } 

    public interface ISomeInterface<T> where T : class 
    { 
     T func(T s); 
    } 

    public class MyStringCollection : ISomeInterface<string> 
    { 
     public string func(string s) 
     { 
      return s; 
     } 
    } 

    public class MyProgramCollection : ISomeInterface<Program> 
    { 
     public Program func(Program s) 
     { 
      return s; 
     } 
    } 

    public class MyXCollection 
    { 
     public int func(int s) 
     { 
      return s; 
     } 
    } 

}