2010-07-23 21 views
7

Tengo un MethodInfo pasados ​​a una función y quiero hacer lo siguiente¿Cómo puedo determinar si un método es un ejemplo genérico de un método genérico

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

Pero esto no funciona debido a que el MethodInfo tiene un tipo genérico específico. El ejemplo funciona si sabía que ICollection siempre era de tipo cadena.

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

¿Cómo puedo comprobar si el MethodInfo es una CUALQUIER mecanografiadas instancia del método genérico, sin preocuparse de lo que es el tipo?

Gracias.

EDIT: aclaración Pregunta

Como señaló correctamente el método no es genérico, pero la clase que contiene es así que la pregunta es más cómo averiguo si el MethodInfo es de un tipo que es una instancia de mecanografiada de ICollection <>.

EDIT: más contexto

Estoy escribiendo un proveedor de LINQ y tratando de manejar el "en" caso

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

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

Respuesta

3

se puede comprobar el tipo declarando:

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

OMI más simple y clara, gracias. –

4

Tenga en cuenta que ICollection<T>.Contains es no un método genérico - es un no -genérico método de un tipo genérico. De lo contrario, IsGenericMethod y GetGenericTypeDefinition ayudarían. Puede obtener la definición de tipo genérico (DeclaringType.GetGenericTypeDefinition()) y volver a trabajar hasta Contains, pero me pregunto si está abordando este problema de la manera difícil.

Por lo general, si está utilizando la reflexión, puede ser pragmática para caer a no genérico IList - a menos que necesidad los datos de tipo (por ejemplo, para meta-programación). Y en ese caso, consideraría mirar de cerca para ver si puede simplificar la configuración aquí.

+0

Gracias por la respuesta.Agregué un poco de contexto arriba para lo que estoy tratando de lograr. El enfoque DeclaringType parece prometedor, lo intentaré y lo recuperaré. –

0

El problema es que no tiene un método genérico: tiene un método no genérico en un tipo genérico. No conozco una manera de usar la reflexión para pasar directamente de una definición de método en un tipo genérico abierto a ese mismo método en un tipo genérico cerrado o viceversa. Sin embargo, se puede aprovechar el hecho de que los métodos devueltos por GetMethods() de los tipos genéricos abiertos y cerrados siempre debe estar en el mismo orden y hacer la traducción por el índice:

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

Habría que agregar alguna verificación de error a esto, pero creo que esto hace más o menos lo que quiere. Puede usar un método con o sin un argumento de tipo como parámetro.

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

probar este método

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; 

    } 

y aquí está el ejemplo de uso completo.

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

} 
Cuestiones relacionadas