2009-02-25 11 views
11

Referenzierung gewünschte überladene generische Methode

gegeben
public Class Example 
{ 

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

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

} 

Fragen:

  1. Ist es richtig, dies eine "überlastet generische Methode" zu nennen?
  2. Wie kann eine Methode bei der Erstellung eines MethodInfo-Objekts angegeben werden?

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

Argument 4 bewirkt, dass der Compiler viel Unmut

+0

Sie fehlen einen Rückgabetyp in Ihren Methodendefinitionen. – Ray

+0

in der Tat, nicht mehr, danke. –

Antwort

11

ich keine Möglichkeit der Verwendung von GetMethod finden können, tun würde, was Sie wollen. Sie können jedoch alle Methoden aufrufen und die Liste durchgehen, bis Sie die gewünschte Methode gefunden haben.

Denken Sie daran, Sie müssen MakeGenericMethod aufrufen, bevor Sie es tatsächlich verwenden können.

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

Hier ist eine Linq Einzeiler für das, was Sie brauchen:

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

Das ist genau das, was ich habe, was ist der Sinn, es neu zu melden? – Ray

+0

während Ray die richtige Strategie für die richtige Methode gefunden hat, danke für die LINQ one-linner –

+0

Ray: Das tut mir wirklich sehr leid. Ich schrieb und testete in VS zur gleichen Zeit wie Sie, nur, ich drückte auf den Senden-Button nach Ihnen. Ich habe die Antwort bearbeitet, um es weniger offensichtlich zu machen, dass ich dich plagiiert habe. – Coincoin

3

Hier sind die Antworten auf Ihre Fragen zusammen mit einem Beispiel:

  1. Ja, obwohl es zwei Dinge wirklich hier mit generischen Methoden zu beachten, Typ Inferenz und Überladung Methode Auflösung. Typinferenz tritt zur Kompilierzeit auf, bevor der Compiler versucht, überladene Methodensignaturen aufzulösen. Der Compiler wendet die Typ-Inferenzlogik auf alle generischen Methoden an, die denselben Namen haben. Im Überladungsauflösungsschritt enthält der Compiler nur die generischen Methoden, auf denen die Typinferenz erfolgreich war. More here...

  2. Bitte beachten Sie die vollständigen Beispiel Konsolenanwendungsprogrammcode unter das zeigt, wie mehrere Varianten des Foo-Methode kann bei der Erstellung eines Objekts Method angegeben werden und dann eine Erweiterung Methode aufgerufen werden:

Programm 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

ein herausragender Beitrag, vielen Dank für das Anlegen der Klinik –

0

Ich mache eine kleine Änderung Ihrer Lambda-Abfrage.

Wenn der Parametertyp si generic Sie, dass so machen müssen:

ich hinzufügen

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; 
pi.ParameterType.GetGenericTypeDefinition()

und

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

Auf diese Weise arbeitet das Verfahren sehr feine

Beispiel:

Mit der Modifikation des Verfahrens i diese Erweiterung Methode

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

Mit meinem neuen Helfer wie diese

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

die Unterschrift meines Helfer nennen kann, ist

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

Bessere :

Beispielversuch, um die korrekte Überladung von System.Linq.Enumerable.Select

zu erhalten
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)) }); 
    }