2008-11-28 8 views
107

Edit:Aufruf der generischen Methode mit einem nur zur Ausführungszeit bekannten Typargument

Natürlich sieht mein echter Code nicht genau so aus. Ich habe versucht, einen Pseudo-Code zu schreiben, um klarer zu machen, was ich tun wollte.

Sieht so aus, als ob es nur Dinge vermasselt.

Also, was ich eigentlich tun, ist dies:

Method<Interface1>(); 
Method<Interface2>(); 
Method<Interface3>(); 
... 

Nun ... Ich dachte, dass vielleicht ich es in eine Schleife mit Reflexion verwandeln könnte. Die Frage ist also: Wie mache ich das? Ich habe sehr seichtes Wissen der Reflexion. Codebeispiele wären also großartig.

Das Szenario sieht wie folgt aus:

public void Method<T>() where T : class 
{} 
public void AnotherMethod() 
{ 
    Assembly assembly = Assembly.GetExecutingAssembly(); 

    var interfaces = from i in assembly.GetTypes() 
    where i.Namespace == "MyNamespace.Interface" // only interfaces stored here 
    select i; 

    foreach(var i in interfaces) 
    { 
     Method<i>(); // Get compile error here! 
    } 




Original-Beitrag:

Hallo!

Ich versuche durch alle Schnittstellen in einem Namespace-Schleife und sie als Argumente für eine generische Methode wie folgt an:

public void Method<T>() where T : class 
{} 
public void AnotherMethod() 
{ 
    Assembly assembly = Assembly.GetExecutingAssembly(); 

    var interfaces = from i in assembly.GetTypes() 
    where i.Namespace == "MyNamespace.Interface" // only interfaces stored here 
    select i; 

    foreach(var interface in interfaces) 
    { 
     Method<interface>(); // Get compile error here! 
    } 
} 

Der Fehler I „Typname erwartet, aber lokale Variablennamen gefunden ". Wenn ich

... 
    foreach(var interface in interfaces) 
    { 
     Method<interface.MakeGenericType()>(); // Still get compile error here! 
    } 
} 

versuche ich bekommen „Kann nicht für Operator‚<‘auf Operanden des Typs‚Methodengruppe‘und‚System.Type‘“ Jede Idee, wie dieses Problem zu bekommen?

Antwort

133

EDIT: Okay, Zeit für ein kurzes aber komplettes Programm. Die grundlegende Antwort ist wie zuvor:

  • Finden Sie die „offene“ generische Methode mit Type.GetMethod
  • Machen Sie es generische Verwendung von Makegenericmethod
  • es Invoke mit Invoke

Hier ist ein Beispielcode. Beachten Sie, dass ich den Abfrageausdruck in Punktnotation geändert habe - es hat keinen Sinn, einen Abfrageausdruck zu verwenden, wenn Sie im Grunde nur eine where-Klausel erhalten haben.

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

namespace Interfaces 
{ 
    interface IFoo {} 
    interface IBar {} 
    interface IBaz {} 
} 

public class Test 
{ 
    public static void CallMe<T>() 
    { 
     Console.WriteLine("typeof(T): {0}", typeof(T)); 
    } 

    static void Main() 
    { 
     MethodInfo method = typeof(Test).GetMethod("CallMe"); 

     var types = typeof(Test).Assembly.GetTypes() 
           .Where(t => t.Namespace == "Interfaces"); 

     foreach (Type type in types) 
     { 
      MethodInfo genericMethod = method.MakeGenericMethod(type); 
      genericMethod.Invoke(null, null); // No target, no arguments 
     } 
    } 
} 

Ursprüngliche Antwort

ist abgesehen von den offensichtlichen Probleme Lassen Sie lassen von einer variablen „Schnittstelle“ zu nennen, mit zu beginnen.

Sie müssen es durch Reflexion aufrufen. Der Punkt von Generika ist es, mehr Typ Überprüfung bei kompilieren Zeit. Sie wissen nicht, was der Typ zur Kompilierzeit ist - deshalb müssen Sie Generika verwenden.

Rufen Sie die generische Methode ab und rufen Sie MakeGenericMethod auf, und rufen Sie sie anschließend auf.

Ist Ihr Interface-Typ selbst eigentlich generisch? Ich frage, weil Sie Makegenerictype auf sie anrufen, aber nicht in jeder Art Argumente zu übergeben ... Versuchen Sie,

Method<MyNamespace.Interface<string>>(); // (Or whatever instead of string) 

oder

Method<MyNamespace.Interface>(); 

zu nennen Falls das letzte ist, was Sie brauchen nur ein Aufruf von MakeGenericMethod - nicht MakeGenericType.

+0

Ich möchte die generische Methode basierend auf dem Typ stub. Aber wenn ich es mit Reflektion mache und dann das erzeugte stubbe, verstehe es, dass es nicht stub was ich will. Meine Vermutung ist, dass es unmöglich ist? Oder ist es? Stub die generische Methode für alle Typen in einer Liste ... –

+1

@Stephane: Es ist schwer zu wissen, genau, was Sie tun möchten. Ich schlage vor, dass Sie eine neue Frage mit mehr Details stellen. –

+0

Beachten Sie, dass in "GetMethod()" eine "mehrdeutige Übereinstimmung in der Methodenauflösung" angezeigt wird. Dies passiert, wenn die Methode, die Sie versuchen zu erhalten, einige Überladungen hat. Sie müssen also mit 'GetMethod (" Name ", new Type [] {arguments})' angeben, welches Sie wollen – cvsguimaraes