web-dev-qa-db-fra.com

<out T> vs <T> in Generics

Quelle est la différence entre <out T> et <T>? Par exemple:

public interface IExample<out T>
{
    ...
}

vs.

public interface IExample<T>
{
    ...
}
160
Cole Johnson

Le mot clé out dans les génériques indique que le type T de l'interface est covariant. Voir Covariance et contravariance pour plus de détails.

L'exemple classique est IEnumerable<out T>. Puisque IEnumerable<out T> est covariant, vous êtes autorisé à effectuer les opérations suivantes:

IEnumerable<string> strings = new List<string>();
IEnumerable<object> objects = strings;

La deuxième ligne ci-dessus échouerait si ce n'était pas une covariante, même si cela devrait fonctionner logiquement, puisque string dérive de object. Avant variance dans les interfaces génériques était ajouté à C # et VB.NET (dans .NET 4 avec VS 2010), il s'agissait d'une erreur de compilation.

Après .NET 4, IEnumerable<T> était marqué covariant et est devenu IEnumerable<out T>. Puisque IEnumerable<out T> utilise uniquement les éléments qu’il contient, et ne les ajoute jamais/ne les modifie pas, il est prudent de traiter une collection énumérable de chaînes comme une collection énumérable d’objets, ce qui signifie qu’elle est covariante .

Cela ne fonctionnerait pas avec un type comme IList<T>, puisque IList<T> a une méthode Add. Supposons que cela soit autorisé:

IList<string> strings = new List<string>();
IList<object> objects = strings;  // NOTE: Fails at compile time

Vous pouvez alors appeler:

objects.Add(new Image()); // This should work, since IList<object> should let us add **any** object

Bien entendu, cela échouerait - alors IList<T> ne peut pas être marqué comme covariant.

Il y a aussi, en passant, une option pour in - qui est utilisée par des choses comme les interfaces de comparaison. IComparer<in T>, par exemple, fonctionne dans le sens opposé. Vous pouvez utiliser un béton IComparer<Foo> directement comme un IComparer<Bar> si Bar est une sous-classe de Foo, car le IComparer<in T> interface est contravariant .

192
Reed Copsey

Pour mémoriser facilement l'utilisation des mots-clés in et out (ainsi que covariance et contravariance), nous pouvons imaginer l'héritage comme enveloppant:

String : Object
Bar : Foo

in/out

52
o0omycomputero0o

considérer,

class Fruit {}

class Banana : Fruit {}

interface ICovariantSkinned<out T> {}

interface ISkinned<T> {}

et les fonctions,

void Peel(ISkinned<Fruit> skinned) { }

void Peel(ICovariantSkinned<Fruit> skinned) { }

La fonction qui accepte ICovariantSkinned<Fruit> pourra accepter ICovariantSkinned<Fruit> ou ICovariantSkinned<Bananna> parce que ICovariantSkinned<T> est une interface covariante et Banana est un type de Fruit,

la fonction qui accepte ISkinned<Fruit> ne pourra accepter que ISkinned<Fruit>.

44
Jodrell

"out T "signifie que le type T est" covariant ". Cela limite le fait que T n'apparaisse que comme une valeur renvoyée (sortante) dans les méthodes de la classe, de l'interface ou de la méthode générique. vous pouvez convertir le type/interface/method en équivalent avec un super-type de T.
Par exemple. ICovariant<out Dog> peut être converti en ICovariant<Animal>.

30
James World

Du lien que vous avez posté ....

Pour les paramètres de type générique, , le mot clé out spécifie que le paramètre de type est covariant .

[~ # ~] éditer [~ # ~] : encore une fois, à partir du lien que vous avez posté

Pour plus d'informations, consultez Covariance et contravariance (C # et Visual Basic). http://msdn.Microsoft.com/en-us/library/ee207183.aspx

5
Brad Cunningham