2009-09-10 13 views
46

Ich möchte meine generische Methode mit einem gegebenen Typ Objekt aufrufen.Wie generische Methode mit einem bestimmten Type-Objekt aufrufen?

void Foo(Type t) 
{ 
    MyGenericMethod<t>(); 
} 

funktioniert offensichtlich nicht.

Wie kann ich es funktionieren lassen?

+0

Nur weil es schwer zu finden ist: Mit 'dynamic' ersparen Sie sich alle fehleranfälligen Reflektionsarbeiten. Die beste Antwort gibt es in der referenzierten Frage: http://stackoverflow.com/a/22441650/143684 – ygoe

Antwort

48

Ihr Codebeispiel funktioniert nicht, da die generische Methode eine Typ-ID erwartet, keine Instanz der Type-Klasse. Sie müssen Reflektion verwenden, es zu tun:

public class Example { 

    public void CallingTest() 
    { 
     MethodInfo method = typeof (Example).GetMethod("Test"); 
     MethodInfo genericMethod = method.MakeGenericMethod(typeof (string)); 
     genericMethod.Invoke(this, null); 

    } 

    public void Test<T>() 
    { 
     Console.WriteLine(typeof (T).Name); 
    } 
} 

im Auge behalten Sie, dass dies sehr spröde ist, würde ich eher vorschlagen, ein anderes Muster zu finden Ihre Methode aufzurufen.

Eine weitere hacky-Lösung (vielleicht jemand kann es ein bisschen sauberer machen) wäre etwas Ausdruck Magie zu verwenden:

public class Example { 

    public void CallingTest() 
    { 
     MethodInfo method = GetMethod<Example>(x => x.Test<object>()); 
     MethodInfo genericMethod = method.MakeGenericMethod(typeof (string)); 
     genericMethod.Invoke(this, null); 

    } 

    public static MethodInfo GetMethod<T>(Expression<Action<T>> expr) 
    { 
     return ((MethodCallExpression) expr.Body) 
      .Method 
      .GetGenericMethodDefinition(); 
    } 

    public void Test<T>() 
    { 
     Console.WriteLine(typeof (T).Name); 
    } 
} 

Hinweis Übergabe die ‚Objekt‘ Typkennung als Gattungstypargument in dem Lambda. Konnte nicht so schnell herausfinden, wie man das schafft. So oder so, das ist kompilierungssicher, denke ich. Es fühlt sich einfach irgendwie falsch an:/

+0

Was ist "Programm"? – codymanix

+0

Mein Fehler, ich habe einige Namen geändert (getestet in einer Standard-C# -Konsolen-App, daher heißt die Klasse Programm;)) Es wurde für Sie korrigiert, es sollte der Name der Klasse sein, für die Sie die Methode aufrufen möchten. –

+1

Tolle Idee mit den Expressions. Ich kann mir auch keinen Weg vorstellen, auf eine generische Methode zu verweisen, ohne mindestens ein generisches Dummy-Argument anzugeben. – codymanix

-2

Dieser Ansatz wird nicht funktionieren. Der Grund dafür ist, dass Typ ein Objekt ist, dessen Typ zur Laufzeit bestimmt wird. Sie versuchen jedoch, eine generische Methode aufzurufen. Der Typ eines generischen Methodenaufrufs wird zur Kompilierzeit festgelegt. Daher kann ein Type-Objekt niemals für einen Typparameter einer generischen Methode verwendet werden.

+2

Was ist dann die Lösung? Ich bin auch in diesem Thema so sehr. Vielen Dank. – Tarik

15

Sie müssen Reflexion verwenden, leider (aus den Gründen Jared erwähnt). Zum Beispiel:

MethodInfo method = typeof(Foo).GetMethod("MyGenericMethod"); 
method = method.MakeGenericMethod(t); 
method.Invoke(this, new object[0]); 

Offensichtlich werden Sie mehr Fehler in der Realität überprüft wollen :)


Randbemerkung: mein lokaler MSDN ist nicht festgelegt, dass der Parameter von Makegenericmethod ein Parameter-Array ist, so ich hätte zu verlangen erwartet:

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

aber es scheint, es ist ein Parameter-Array in der Realität, und die online MSDN docs zustimmen. Ungerade.

+1

argghh! Der Skeet hat mich geschlagen:/ –

+0

Danke für die Antwort, Jon. Aber ich habe bereits die richtige Methode angegeben, warum muss ich sie beim Namen laden? Gibt es keinen sichereren Weg, der keine Methodennamen als Strings enthält? – codymanix

+0

Cody: Ich habe eine andere Alternative in meiner Antwort hinzugefügt (Versuch, den Skeet zu besiegen), die keine Strings beinhaltet. Es ist nicht so sauber wie ich es möchte, aber die Idee ist klar, denke ich. –

Verwandte Themen