2010-12-14 7 views
9

tengo este tipo que contiene dos sobrecargas de un método genérico. Me gusta para recuperar una de las sobrecargas (con el parámetro Func<T>) que utilizan la reflexión. El problema sin embargo es que no puedo encontrar el tipo de parámetro correcto para suministrar el método Type.GetMethod(string, Type[]) con.Recuperando el MethodInfo de de la sobrecarga correcta de un método genérico

Aquí es mi definición de clase:

public class Foo 
{ 
    public void Bar<T>(Func<T> f) { } 
    public void Bar<T>(Action<T> a) { } 
} 

Y esto es lo que he llegado con, lamentablemente sin éxito:

[TestMethod] 
public void Test1() 
{ 
    Type parameterType = typeof(Func<>); 

    var method = typeof(Foo).GetMethod("Bar", new Type[] { parameterType }); 

    Assert.IsNotNull(method); // Fails 
} 

¿Cómo puedo obtener el MethodInfo de un método genérico de que conozco los parámetros?

Respuesta

9

¿Por qué no usa los árboles de expresión? Esto lo hace mucho más fácil:

public static MethodInfo GetMethod<T>(
    Expression<Action<T>> methodSelector) 
{ 
    var body = (MethodCallExpression)methodSelector.Body; 
    return body.Method;  
} 

[TestMethod] 
public void Test1() 
{ 
    var expectedMethod = typeof(Foo) 
     .GetMethod("Bar", new Type[] { typeof(Func<>) }); 

    var actualMethod = 
     GetMethod<Foo>(foo => foo.Bar<object>((Func<object>)null) 
     .GetGenericMethodDefinition(); 

    Assert.AreEqual(expectedMethod, actualMethod); 
} 
+0

Guau .. eso es genial.¡Funciona genial! Y tan poco código. – Anne

1

es necesario especificar un tipo concreto utilizando MethodInfo.MakeGenericMethod.

Sin embargo, debo señalar, que conseguir el tipo correcto para invocar MakeGenericMethod complemento no es fácil cuando se tiene un método genérico sobrecargado.

Aquí se muestra un ejemplo:

var method = typeof(Foo) 
       .GetMethods() 
       .Where(x => x.Name == "Bar") 
       .Where(x => x.IsGenericMethod) 
       .Where(x => x.GetGenericArguments().Length == 1) 
       .Where(x => x.GetParameters().Length == 1) 
       .Where(x => 
        x.GetParameters()[0].ParameterType == 
        typeof(Action<>).MakeGenericType(x.GetGenericArguments()[0]) 
       ) 
       .Single(); 

method = method.MakeGenericMethod(new Type[] { typeof(int) }); 

Foo foo = new Foo(); 
method.Invoke(foo, new Func<int>[] {() => return 42; }); 
+0

Eso no ayudará. Él no puede obtener la instancia abierta. – SLaks

+0

¿Me puede mostrar un ejemplo? – Anne

+0

@SLaks: Sí, es posible. Voy a publicar un ejemplo. – jason

1

yo no piensan que pueden hacerlo directamente usando GetMethod. Sospecho que tendrá que iterar sobre todos los métodos llamados Bar, entonces:

  • Comprobar que el método tiene un parámetro de tipo
  • Comprobar que el método tiene un parámetro normal de
  • Utilice el parámetro de tipo de hacer una Func<T> (con typeof(Func<>).MakeGenericType) y comprobar que el tipo de parámetro que coincide.

LINQ es bueno para este tipo de cosas. muestra completa:

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

public class Foo 
{ 
    public void Bar<T>(Func<T> f) { } 
    public void Bar<T>(Action<T> a) { } 
} 

class Test 
{ 
    static void Main() 
    { 
     var methods = from method in typeof(Foo).GetMethods() 
         where method.Name == "Bar" 
         let typeArgs = method.GetGenericArguments() 
         where typeArgs.Length == 1 
         let parameters = method.GetParameters() 
         where parameters.Length == 1 
         where parameters[0].ParameterType == 
          typeof(Func<>).MakeGenericType(typeArgs[0]) 
         select method; 

     Console.WriteLine("Matching methods..."); 
     foreach (var method in methods) 
     { 
      Console.WriteLine(method); 
     } 
    } 
} 

Básicamente los genéricos y la reflexión son realmente desagradable en combinación, me temo :(

4

Sorprendentemente, parece que tendrá que llamar GetMethods() y lazo sobre los métodos hasta que encuentre el que desea

Por ejemplo:

var yourMethod = typeof(Foo).GetMethods() 
    .First(m => m.Name == "Bar" 
      && m.GetParameters().Length == 1 
      && m.GetParameters()[0].ParameterType.ContainsGenericParameters 
      && m.GetParameters()[0].ParameterType.GetGenericTypeDefinition() == typeof(Func<>)); 
+0

Funciona. Gracias. – Anne

0

podrá lucha con sólo con sólo GetMethod - usted podría intentar algo a lo largo de la lin. es de;

var method = (from m in typeof(Foo).GetMethods() 
    where 
    m.IsGenericMethodDefinition == true && 
    m.Name == "Bar" && 
    m.GetParameters().Length > 0 && 
    m.GetParameters()[0].ParameterType.GetGenericTypeDefinition() == parameterType 
    select m).FirstOrDefault(); 
Cuestiones relacionadas