2009-03-28 20 views
25

Ich schreibe .NET On-the-Fly Compiler für CLR-Scripting und wollen Hinrichtungsmethode machen generic akzeptabel:Operator wie und generische Klassen

object Execute() 
{ 
    return type.InvokeMember(..); 
} 

T Execute<T>() 
{ 
    return Execute() as T; /* doesn't work: 
    The type parameter 'T' cannot be used with the 'as' operator because 
    it does not have a class type constraint nor a 'class' constraint */ 

    // also neither typeof(T) not T.GetType(), so on are possible 

    return (T) Execute(); // ok 
} 

Aber ich denke, Operator as wird sehr nützlich sein: Wenn Ergebnistyp nicht T Methode ist gibt null statt einer Ausnahme zurück! Ist es möglich zu tun?

Antwort

49

Sie benötigen

where T : class 

auf Ihre Methode Erklärung hinzuzufügen, zum Beispiel

T Execute<T>() where T : class 
{ 

Übrigens, als Vorschlag, dass generische Wrapper nicht wirklich viel Wert hinzufügen. Der Anrufer kann schreiben:

MyClass c = whatever.Execute() as MyClass; 

Oder wenn sie auf werfen wollen fehlschlagen:

MyClass c = (MyClass)whatever.Execute(); 

Die allgemeine Wrapper Methode sieht wie folgt aus:

MyClass c = whatever.Execute<MyClass>(); 

Alle drei Varianten haben genau angeben, die gleichen drei Entitäten, nur in verschiedenen Ordnungen, so dass keine einfacher oder bequemer sind, und doch verbirgt die generische Version, was passiert, während die "rohen" Versionen jeweils klar machen, ob es w sei ein Wurf oder ein null.

(Dies kann für Sie irrelevant sein, wenn Ihr Beispiel von Ihrem tatsächlichen Code vereinfacht wird).

+0

Vielen Dank für Ihre Antwort. Ich werde es benutzen, überprüfen und als Antwort markieren. Und ich habe als nächstes meine Code-Verwendung: MyClass c = compiler.Execute (); Ich denke, es ist besser als MyClass c = compiler.Execute() als MyClass; (check drinnen ist besser als draussen, schätze ich) – abatishchev

+0

Aber der Check wird noch draußen gebraucht - der Check für null! :) Indem Sie den Benutzer dazu bringen, 'als MyClass' zu schreiben, verdeutlichen Sie, dass die Überprüfung auf Null erforderlich ist. –

+0

Hm .. Es scheint, dass Sie Recht haben! Ich empfehle, 'normal' Execute() zu verwenden, aber für den Endbenutzer könnte es hilfreich sein, solche 'abnormalen' Execute(), zusätzlich 'generische Experimente' irgendwie zu haben :) – abatishchev

11

Sie können den Operator as nicht mit einem generischen Typ ohne Einschränkung verwenden. Da der Operator as mit null angibt, dass er nicht vom Typ ist, können Sie ihn nicht für Werttypen verwenden. Wenn Sie obj as T, T verwenden möchten, müssen als Referenztyp haben.

1

Es scheint, als ob Sie nur eine Wrapper-Methode zum Umwandeln in den vom Benutzer gewünschten Typ hinzufügen, wodurch nur Overhead zur Ausführung hinzugefügt wird. Für den Anwender ist

int result = Execute<int>(); 

Schreiben nicht viel anders aus

int result = (int)Execute(); 

Sie den Modifikator aus kann das Ergebnis in eine Variable in dem Anrufer Umfang und gibt einen boolean-Flag schreiben um festzustellen, ob es erfolgreich war:

bool Execute<T>(out T result) where T : class 
{ 
    result = Execute() as T; 
    return result != null; 
} 
1

Gibt es eine Chance, dass Execute() einen Werttyp zurückgeben kann? Wenn dies der Fall ist, benötigen Sie die Earwicker-Methode für Klassentypen und eine weitere generische Methode für Werttypen.aussehen könnte wie folgt:

Nullable<T> ExecuteForValueType<T> where T : struct 

Die Logik innerhalb dieser Methode

object rawResult = Execute(); 

Dann sagen würde, würden Sie die Art der rawResult bekommen müssen und sehen, ob es T zugeordnet werden können:

Schließlich, machen Sie Ihre ursprüngliche Execute Nachricht herauszufinden, welche T hat (Klasse oder Strukturtyp), und rufen Sie die entsprechende Implementierung.

Hinweis: Dies ist aus grober Speicher. Ich habe das vor einem Jahr gemacht und erinnere mich wahrscheinlich nicht an jedes Detail. Trotzdem hoffe ich dich in die allgemeine Richtung zu lenken.