2010-04-19 15 views
6

Betrachten habe ich die folgenden drei Klassen/Schnittstellen:Casting Generika und der generische Typ

class MyClass<T> { } 

interface IMyInterface { } 

class Derived : IMyInterface { } 

Und ich will ein MyClass<Derived> in ein MyClass<IMyInterface> oder Visum versa werfen können:

MyClass<Derived> a = new MyClass<Derived>(); 
MyClass<IMyInterface> b = (MyClass<IMyInterface>)a; 

Aber ich Compiler-Fehler, wenn ich versuche:

Cannot convert type 'MyClass<Derived>' to 'MyClass<IMyInterface>' 

ich bin sicher, dass es eine sehr gute re Warum kann ich das nicht, aber ich kann mir keinen vorstellen.

Warum ich das machen möchte - Das Szenario, das ich mir vorstelle, ist eines, bei dem Sie idealerweise mit einer Instanz von MyClass<Derived> arbeiten möchten, um viele böse Würfe zu vermeiden, jedoch müssen Sie Ihre Instanz an eine übergeben Schnittstelle, die MyClass<IMyInterface> akzeptiert.

So ist meine Frage zweierlei:

  • Warum kann ich nicht zwischen diesen beiden Typen werfen?
  • Gibt es eine Möglichkeit, die Nettigkeit des Arbeitens mit einer Instanz von MyClass<Derived> beizubehalten und trotzdem in eine MyClass<IMyInterface> zu werfen?

Antwort

5

Dies funktioniert nicht, da C# nur die Kovarianz der Typparameter von Schnittstellen und Delegaten unterstützt. Wenn Ihr Typ-Parameter nur in Ausgangspositionen vorhanden ist (dh Sie nur zurückgeben Instanzen davon aus Ihrer Klasse und nehmen es nicht als Argument) Sie eine Schnittstelle wie diese schaffen könnte:

interface IClass<out T> { } 
class MyClass<T> : IClass<T> { } 

die es Ihnen erlauben würde, Dazu:

IClass<Derived> a = new MyClass<Derived>(); 
IClass<IMyInterface> b = a; 

Ehrlich gesagt, dass etwa so nah wie Sie bekommen werden, und dies erfordert die C# 4 Compiler zu arbeiten.

3

Der Grund, warum Sie dies nicht tun können, ist, weil die meisten Klassen keine einfachen leeren Beispiele sind. Sie haben Methoden:

class MyClass<T> 
{ 
    static T _storage; 

    public void DoSomethingWith(T obj) 
    { 
     _storage = obj; 
    } 
} 

interface IMyInterface { } 

class Derived : IMyInterface { } 

MyClass<Derived> a = new MyClass<Derived>(); 

Nun hat a ein Verfahren DoSomethingWith die Derived eine Derived und speichert sie in einer statischen Variablen des Typs akzeptiert.

MyClass<IMyInterface> b = (MyClass<IMyInterface>)a; 

Wenn das erlaubt wäre, würde b erscheinen nun ein Verfahren DoSomethingWith zu haben, die etwas akzeptiert, die IMyInterface implementiert, und würde dann intern Versuch, es in einer statischen Variablen des Typs zu speichern Derived, weil es immer noch wirklich ist das gleiche Objekt, auf das sich a bezieht.

So, jetzt hätten Sie eine Variable vom Typ Derived speichern ... wer weiß was.