2010-04-19 12 views
6

Tenir compte, j'ai les 3 classes/interfaces suivantes:génériques coulée et le type générique

class MyClass<T> { } 

interface IMyInterface { } 

class Derived : IMyInterface { } 

Et je veux être en mesure de jeter un MyClass<Derived> dans un MyClass<IMyInterface> ou visa versa:

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

Mais je reçois des erreurs du compilateur si je tente:

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

Je suis sûr qu'il ya une très bonne nouvelle pourquoi je ne peux pas faire cela, mais je ne peux pas penser à un. Pour ce que je veux faire - Le scénario que j'imagine est celui dans lequel vous voulez idéalement travailler avec une instance de MyClass<Derived> afin d'éviter beaucoup de lancers méchants, mais vous devez passer votre instance à une instance de MyClass<Derived>. interface qui accepte MyClass<IMyInterface>.

Donc, ma question est double:

  • Pourquoi ne puis-je pas jeté entre ces deux types?
  • Existe-t-il un moyen de garder la gentillesse de travailler avec une instance de MyClass<Derived> tout en étant capable de transformer ceci en MyClass<IMyInterface>?

Répondre

5

Cela ne fonctionne pas car C# ne prend en charge que la covariance sur les paramètres de type des interfaces et des délégués. Si votre paramètre de type existe uniquement dans des positions de sortie (vous revenez seulement des cas de celui-ci de votre classe et ne l'acceptez pas comme argument), vous pouvez créer une interface comme ceci:

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

qui vous permettra de faire:

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

Honnêtement qui est à peu près aussi proche que vous allez obtenir ce qui nécessite le compilateur C# 4 pour travailler.

3

La raison pour laquelle vous ne pouvez pas faire cela en général est que la plupart des classes ne sont pas de simples exemples vides. Ils ont des méthodes:

class MyClass<T> 
{ 
    static T _storage; 

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

interface IMyInterface { } 

class Derived : IMyInterface { } 

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

Maintenant, a a une méthode DoSomethingWith qui accepte un Derived et le stocke dans une variable statique de type Derived.

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

Si cela était permis, b semblerait maintenant d'avoir une méthode DoSomethingWith qui accepte quoi que ce soit qui implémente IMyInterface, et serait alors en interne pour tenter de le stocker dans une variable statique de type Derived, car il est encore vraiment le même objet visé par a. Maintenant, vous auriez une variable de type Derived qui stocke ... qui sait quoi.