2010-07-23 7 views
7

Ho un MethodInfo passata a una funzione e voglio fare quanto segueCome faccio a determinare se un metodo è un'istanza generica di un metodo generico

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

Ma questo non funziona perché il MethodInfo ha un tipo generico specifico. Ad esempio, funziona se avessi saputo che ICollection era sempre di tipo string.

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

Come si può verificare se il MethodInfo è un QUALSIASI digitato istanza del metodo generico, senza preoccuparsi di ciò che il tipo è?

Grazie.

EDIT: Domanda chiarimento

Come ha giustamente osservato il metodo non è generico, ma la classe che contiene è quindi la domanda è più come scopro se il MethodInfo è per un tipo che è un'istanza tipizzata di ICollection <>.

EDIT: più contesto

Sto scrivendo un fornitore di Linq e cercando di gestire la "in" caso

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

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

risposta

3

Si potrebbe verificare il tipo di dichiarazione:

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

IMO più semplice e chiaro, grazie. –

4

noti che ICollection<T>.Contains è non un metodo generico - si tratta di una non -generico metodo di un tipo generico. Altrimenti IsGenericMethod e GetGenericTypeDefinition sarebbero d'aiuto. È possibile ottenere la definizione di tipo generico (DeclaringType.GetGenericTypeDefinition()) e tornare a Contains, ma mi chiedo se si sta affrontando questo problema nel modo più difficile.

Di solito, se si sta utilizzando la riflessione, può essere pragmatico per scendere a non generico IList - a meno che non necessità i dati tipo (ad esempio, per la meta-programmazione). E in tal caso, prenderei in considerazione la possibilità di guardare da vicino per vedere se è possibile semplificare la configurazione qui.

+0

Grazie per la risposta.Aggiunto qualche contesto sopra per quello che sto cercando di ottenere. L'approccio DeclaringType sembra promettente, lo proverò e tornerò. –

0

Il problema è che non si dispone di un metodo generico: si dispone di un metodo non generico su un tipo generico. Non conosco un modo per utilizzare la riflessione per passare direttamente da una definizione di metodo su un tipo generico aperto a quello stesso metodo su un tipo generico chiuso o viceversa. Tuttavia, si può approfittare del fatto che i metodi restituiti da GetMethods() sui tipi generici aperti e chiusi dovrebbe essere sempre nello stesso ordine e fare la traduzione per indice:

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

Alcuni controllo degli errori dovrebbe essere aggiunto a questo, ma credo che questo lo fa più o meno ciò che si desidera. È possibile utilizzare un metodo con o senza un argomento di tipo come parametro.

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

provare questo metodo

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; 

    } 

e qui è il pieno utilizzo esempio.

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

}