2010-05-11 35 views
6

Puis-je avoir un type (pour l'instant oublier sa sémantique) qui peut être covariant ainsi que contravariant?Puis-je avoir un type à la fois covariant et contravariant, c'est-à-dire entièrement fongible/modifiable avec les types sub et super?

par exemple:

public interface Foo<in out T> 
{ 
    void DoFooWith(T arg); 
} 

Off sur le blog de Eric Lippert pour la viande et les pommes de terre de la variance dans C# 4.0 comme il y a peu d'autre part, qui couvre bien du terrain sur le sujet. Je l'ai essayé de toute façon, non seulement cela ne le permet pas, mais il me dit qu'il me manque tout le point. J'ai besoin de comprendre le lien entre lecture seule, écriture seule et variance. Je suppose que j'ai eu plus de lecture à faire.

Mais toutes les courtes réponses qui suscitent l'épiphanie sont les bienvenues.

Répondre

7

Non, vous ne pouvez pas faire cela.

Supposons que c'était légal. Vous faites un IFoo<Giraffe>. Puisque IFoo est covariant dans T, vous pouvez le convertir via la conversion de référence de typesafe en IFoo<object>. Comme il est contravariant, vous pouvez le convertir en IFoo<Banana>. Quelle sémantique possible existe-t-il pour IFoo<T> de sorte qu'il est logique de pouvoir convertir un IFoo de Girafes en un IFoo de Bananas via la conversion de référence? Les girafes et les bananes n'ont rien de commun à part être des types de référence. Vous ne pouvez pas avoir une méthode sur IFoo<Banana> qui renvoie un banana, car il peut être une implémentation de IFoo<Giraffe>; Comment l'auteur de l'implémentation sait-il comment distribuer une banane? Vous ne pouvez pas avoir une méthode sur IFoo<Banana> qui prend une banane pour la même raison; l'implémenteur de IFoo<Giraffe> vous attend pour lui remettre une girafe.

Voici une autre façon de regarder:

  • "T" des moyens (environ) "T apparaît uniquement dans des positions d'entrée". "Out T" signifie (grossièrement) "T n'apparaît que dans les positions de sortie"

Par conséquent, "in out" signifierait ... quoi? Comme nous l'avons déjà vu, cela ne peut vouloir dire que «T n'apparaît dans aucune méthode ou propriété». Quel est le point de faire un type générique dans T où vous n'utilisez jamais T?

+1

En fait, les types génériques qui n'utilisent pas leurs arguments de type générique peuvent être extrêmement utiles. Les soi-disant «types fantômes» permettent d'écrire du code de telle manière que des opérations incorrectes peuvent être interdites statiquement. L'exemple canonique est probablement un type 'File ', où le type 'T' code si le fichier autorise la lecture, l'écriture, ou les deux, même si les internes de la classe ne font jamais référence à' T'. – kvb

+0

Bien sûr, vous pourriez facilement violer l'avantage de sécurité des types fantômes si le type a été annoté à la fois covariant et contravariant, puisque vous pourriez alors convertir un fichier '' Fichier ', comme vous le notez. – kvb

+2

@kvb: En quoi est-ce différent de simplement créer un fichier de classe de base et des classes dérivées "WritableFile", "ReadableFile" et "ReadableAndWritableFile"? Pourquoi capturer quelque chose dans le système de type générique quand il pourrait simplement être capturé dans le système de type ordinaire? –