2009-02-25 12 views
11

dadoreferencia deseada método genérico sobrecargado

public Class Example 
{ 

public static void Foo< T>(int ID){} 

public static void Foo< T,U>(int ID){} 

} 

Preguntas:

  1. ¿Es correcto llamar a esto un "método genérico sobrecargado"?
  2. ¿Cómo se puede especificar cualquiera de los métodos en la creación de un objeto MethodInfo?

    Type exampleType = Type.GetType("fullyqualifiednameOfExample, namespaceOfExample"); 
    MethodInfo mi = exampleType.GetMethod("Foo", BindingFlags.Public|BindingFlags.Static, null, new Type[] {typeof(Type), typeof(Type) }, null); 
    

argumento 4 hace que el compilador mucho descontento

+0

que se está perdiendo un tipo de retorno en sus definiciones de métodos. – Ray

+0

de hecho, ya no, gracias. –

Respuesta

11

no puedo encontrar una manera de usar GetMethod que hacer lo que quiera. Pero puede obtener todos los métodos y revisar la lista hasta que encuentre el método que desea.

Recuerde que necesita llamar a MakeGenericMethod antes de poder usarlo.

var allMethods = typeof (Example).GetMethods(BindingFlags.Public | BindingFlags.Static); 
MethodInfo foundMi = allMethods.FirstOrDefault(
    mi => mi.Name == "Foo" && mi.GetGenericArguments().Count() == 2); 
if (foundMi != null) 
{ 
    MethodInfo closedMi = foundMi.MakeGenericMethod(new Type[] {typeof (int), typeof (string)}); 
    Example example= new Example(); 
    closedMi.Invoke(example, new object[] { 5 }); 
} 
1

Aquí es una LINQ de una sola línea de lo que necesita:

MethodInfo mi = exampleType.GetMethods().First(m=>m.GetGenericArguments().Length == 2); 
+0

Eso es exactamente lo que tengo, ¿qué sentido tiene volver a publicarlo? – Ray

+0

mientras que Ray identificó la estrategia correcta de susear el método correcto, gracias por LINQ one-linner –

+0

Ray: Realmente lo siento mucho. Estuve escribiendo y probando en VS al mismo tiempo que usted, solo presioné el botón de enviar después de usted. Edité la respuesta para que no fuera tan obvio que te plagié. – Coincoin

3

Estas son las respuestas a sus preguntas, junto con un ejemplo:

  1. Sí, aunque hay Dos cosas realmente importantes aquí con métodos genéricos, tipo de inferencia y resolución de método de sobrecarga. La inferencia de tipo se produce en tiempo de compilación antes de que el compilador intente resolver las firmas de método sobrecargadas. El compilador aplica lógica de inferencia de tipo a todos los métodos genéricos que comparten el mismo nombre. En el paso de resolución de sobrecarga, el compilador incluye solo aquellos métodos genéricos en los que la inferencia de tipo tuvo éxito. More here...

  2. Por favor, consulte el artículo completo ejemplo código de programa de aplicación de consola de abajo que muestra cómo varias variantes del método de Foo se pueden especificar en la creación de un objeto MethodInfo y luego invocados mediante un método de extensión:

Programa cs

class Program 
{ 
    static void Main(string[] args) 
    { 
     MethodInfo foo1 = typeof(Example).GetGenericMethod("Foo", 
      new[] { typeof(string) }, 
      new[] { typeof(int) }, 
      typeof(void)); 

     MethodInfo foo2 = typeof(Example).GetGenericMethod("Foo", 
      new[] { typeof(string), typeof(int) }, 
      new[] { typeof(int) }, 
      typeof(void)); 

     MethodInfo foo3 = typeof(Example).GetGenericMethod("Foo", 
      new[] { typeof(string) }, 
      new[] { typeof(string) }, 
      typeof(void)); 

     MethodInfo foo4 = typeof(Example).GetGenericMethod("Foo", 
      new[] { typeof(string), typeof(int) }, 
      new[] { typeof(int), typeof(string) }, 
      typeof(string)); 

     Console.WriteLine(foo1.Invoke(null, new object[] { 1 })); 
     Console.WriteLine(foo2.Invoke(null, new object[] { 1 })); 
     Console.WriteLine(foo3.Invoke(null, new object[] { "s" })); 
     Console.WriteLine(foo4.Invoke(null, new object[] { 1, "s" })); 
    } 
} 

Example.cs:

public class Example 
{ 
    public static void Foo<T>(int ID) { } 
    public static void Foo<T, U>(int ID) { } 
    public static void Foo<T>(string ID) { } 
    public static string Foo<T, U>(int intID, string ID) { return ID; } 
} 

Extensions.cs:

public static class Extensions 
{ 
    public static MethodInfo GetGenericMethod(this Type t, string name, Type[] genericArgTypes, Type[] argTypes, Type returnType) 
    { 
     MethodInfo foo1 = (from m in t.GetMethods(BindingFlags.Public | BindingFlags.Static) 
          where m.Name == name && 
          m.GetGenericArguments().Length == genericArgTypes.Length && 
          m.GetParameters().Select(pi => pi.ParameterType).SequenceEqual(argTypes) && 
          m.ReturnType == returnType 
          select m).Single().MakeGenericMethod(genericArgTypes); 

     return foo1; 
    } 
} 
+0

una publicación destacada, gracias por poner en la clínica –

0

hago una pequeña modificación de la consulta lambda.

Cuando el tipo de parámetro si genérica que debe hacer que, al igual que:

agrego pi.ParameterType.GetGenericTypeDefinition()

y

(m.ReturnType.IsGenericType ? m.ReturnType.GetGenericTypeDefinition() : m.ReturnType) == returnType) 

De esta manera, el método de trabajo muy fino

MethodInfo foo1 = (from m in t.GetMethods(BindingFlags.Public | BindingFlags.Static) 
         where m.Name == name 
         && m.GetGenericArguments().Length == genericArgTypes.Length 
         && m.GetParameters().Select(pi => pi.ParameterType.IsGenericType ? pi.ParameterType.GetGenericTypeDefinition() : pi.ParameterType).SequenceEqual(argTypes) && 
         (returnType==null || (m.ReturnType.IsGenericType ? m.ReturnType.GetGenericTypeDefinition() : m.ReturnType) == returnType) 
         select m).FirstOrDefault(); 
     if (foo1 != null) 
     { 
     return foo1.MakeGenericMethod(genericArgTypes); 
     } 
     return null; 

Ejemplo:

Con la modificación del método que pueda llamar esta extensión método

public static IQueryable<T> FilterCulture<T>(this Table<T> t, IDatabaseFilter filter) 

Con mi nuevo ayudante como esto

var QueryableExpression = MethodInfoHelper.GetGenericMethod(typeof(LinqFilterExtension), "FilterCulture", new Type[] { rowType }, new Type[] { typeof(Table<>), typeof(IDatabaseFilter) }, typeof(IQueryable<>)); 

La firma de mi ayudante es

public static MethodInfo GetGenericMethod(Type t, string name, Type[] genericArgTypes, Type[] argTypes, Type returnType) 
1

Mejor :

Ejemplo intento de obtener la sobrecarga correcta de System.Linq.Enumerable.Select

private static MethodInfo GetMethod<T>(Expression<Func<T>> expression) 
    { 
     return ((MethodCallExpression)expression.Body).Method; 
    } 

    public static void CallSelect() 
    { 
     MethodInfo definition = GetMethod(() => Enumerable.Select(null, (Func<object, object>)null)).GetGenericMethodDefinition(); 
     definition.MakeGenericMethod(typeof(int), typeof(int)).Invoke(null, new object[] { new List<int>(), ((Func<int, int>)(x => x)) }); 
    } 
Cuestiones relacionadas