2011-03-01 11 views
7

Quiero enumerar todos los métodos de un tipo con una firma de método específica.Obtener solo métodos con firma específica de Type.GetMethods()

Por ejemplo, si un tipo tiene algunos métodos públicos: public void meth1 (int i); public void meth2 (int i, string s); public void meth3 (int i, string s); public int meth4 (int i, string s);

Quiero enumerar todos los métodos que esperan una int como primera y una cadena como segundo parámetro y devuelve vacío.

¿Cómo puedo hacer esto?

Respuesta

12

Puede usar algo como esto:

public static class Extensions 
{ 
    public static IEnumerable<MethodInfo> GetMethodsBySig(this Type type, Type returnType, params Type[] parameterTypes) 
    { 
     return type.GetMethods().Where((m) => 
     { 
      if (m.ReturnType != returnType) return false; 
      var parameters = m.GetParameters(); 
      if ((parameterTypes == null || parameterTypes.Length == 0)) 
       return parameters.Length == 0; 
      if (parameters.Length != parameterTypes.Length) 
       return false; 
      for (int i = 0; i < parameterTypes.Length; i++) 
      { 
       if (parameters[i].ParameterType != parameterTypes[i]) 
        return false; 
      } 
      return true; 
     }); 
    } 
} 

Y utilizar de esta manera:

var methods = this.GetType().GetMethodsBySig(typeof(void), typeof(int), typeof(string)); 
4

Deberá inspeccionar todos los MethodInfo s usted mismo. Al llamar al MethodInfo.GetParameters() obtendrá una colección de objetos ParameterInfo, que a su vez tienen una propiedad ParameterType.

Lo mismo para el tipo de devolución: inspeccione la propiedad ReturnType de MethodInfo.

1

Dada esta clase:

public class Foo 
{ 
    public void M1(int i){} 
    public void M2(int i, string s){} 
    public void M3(int i, string s){} 
    public int M4(int i, string s){ return 0; } 
} 

Un poco de reflexión y LINQ se puede utilizar:

Type t = typeof (Foo); 
var theMethods = t.GetMethods().Where(mi => 
          { 
           var p = mi.GetParameters(); 
           if (p.Length != 2) 
            return false; 

           if (p[0].ParameterType != typeof(int) 
            || p[1].ParameterType != typeof(string)) 
            return false; 

           return mi.ReturnType == typeof (void); 
          }); 

o la otra sintaxis (que en realidad es más agradable en este caso)

var theMethods = from mi in t.GetMethods() 
        let p = mi.GetParameters() 
        where p.Length == 2 
         && p[0].ParameterType == typeof (int) 
         && p[1].ParameterType == typeof (string) 
         && mi.ReturnType == typeof (void) 
        select mi; 

Prueba:

foreach (var methodInfo in theMethods) 
{ 
    Console.WriteLine(methodInfo.Name); 
} 

Salida:

M2 
M3 
6
type.GetMethods().Where(p => 
       p.GetParameters().Select(q => q.ParameterType).SequenceEqual(new Type[] { typeof(int), typeof(string) }) && 
       p.ReturnType == typeof(void) 
      ); 
+0

er ... mi respuesta fue LINQ, sólo una sintaxis ligeramente diferente. – Jamiec

+0

ok - más linqified ... haciendo uso de la secuencia igual en lugar de escribirla como lamba ... Cambiaré el comentario. –

0

Este es el método de extensión para usar mejorado a partir de la respuesta de EvgK.

private static IEnumerable<MethodInfo> GetMethodsBySig(this Type type, 
                   Type returnType, 
                   Type customAttributeType, 
                   bool matchParameterInheritence, 
                   params Type[] parameterTypes) 
     { 
      return type.GetMethods().Where((m) => 
      { 
       if (m.ReturnType != returnType) return false; 

      if ((customAttributeType != null) && (m.GetCustomAttributes(customAttributeType, true).Any() == false)) 
       return false; 

      var parameters = m.GetParameters(); 

      if ((parameterTypes == null || parameterTypes.Length == 0)) 
       return parameters.Length == 0; 

      if (parameters.Length != parameterTypes.Length) 
       return false; 

      for (int i = 0; i < parameterTypes.Length; i++) 
      { 
       if (((parameters[i].ParameterType == parameterTypes[i]) || 
       (matchParameterInheritence && parameterTypes[i].IsAssignableFrom(parameters[i].ParameterType))) == false) 
        return false; 
      } 

      return true; 
     }); 
    } 

usarlo como

var methods = SomeTypeToScan.GetMethodsBySig(
       typeof(SomeReturnType), 
       typeof(SomeSpecialAttributeMarkerType), 
       true, 
       typeof(SomeParameterType)) 
       .ToList(); 
Cuestiones relacionadas