Quelle est la différence entre <out T>
et <T>
? Par exemple:
public interface IExample<out T>
{
...
}
contre.
public interface IExample<T>
{
...
}
c#
generics
covariance
Cole Johnson
la source
la source
Réponses:
Le
out
mot-clé en générique est utilisé pour indiquer que le type T dans l'interface est covariant. Voir Covariance et contravariance pour plus de détails.L'exemple classique est
IEnumerable<out T>
. PuisqueIEnumerable<out T>
est covariant, vous êtes autorisé à effectuer les opérations suivantes:La deuxième ligne ci-dessus échouerait si ce n'était pas covariant, même si logiquement cela devrait fonctionner, puisque string dérive de object. Avant l' ajout de la variance dans les interfaces génériques à C # et VB.NET (dans .NET 4 avec VS 2010), il s'agissait d'une erreur de compilation.
Après .NET 4, a
IEnumerable<T>
été marqué comme covariant et est devenuIEnumerable<out T>
. CommeIEnumerable<out T>
il n'utilise que les éléments qu'il contient, et ne les ajoute / ne change jamais, 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>
, carIList<T>
a uneAdd
méthode. Supposons que cela soit autorisé:Vous pourriez alors appeler:
Cela échouerait, bien sûr, et ne
IList<T>
peut donc pas être marqué comme covariant.Il y a aussi, btw, 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 inverse. Vous pouvez utiliser un bétonIComparer<Foo>
directement commeIComparer<Bar>
siBar
est une sous-classe deFoo
, car l'IComparer<in T>
interface est contravariante .la source
Image
est une classe abstraite;) Vous pouvez le fairenew List<object>() { Image.FromFile("test.jpg") };
sans problème, ou vous pouvez le fairenew List<object>() { new Bitmap("test.jpg") };
aussi. Le problème avec le vôtre est que cenew Image()
n'est pas autorisé (vous ne pouvez pas le faire nonvar img = new Image();
plus)IList<object>
est un exemple bizarre, si vous voulez desobject
génériques, vous n'avez pas besoin de génériques.Pour se souvenir facilement de l'utilisation de
in
et duout
mot - clé (également covariance et contravariance), nous pouvons représenter l'héritage comme un wrapping:la source
considérer,
et les fonctions,
La fonction qui accepte
ICovariantSkinned<Fruit>
pourra accepterICovariantSkinned<Fruit>
ouICovariantSkinned<Bananna>
carICovariantSkinned<T>
est une interface covariante etBanana
est un type deFruit
,la fonction qui accepte
ISkinned<Fruit>
ne pourra accepterISkinned<Fruit>
.la source
"
out T
" signifie que ce typeT
est "covariant". Cela limiteT
à apparaître uniquement comme une valeur retournée (sortante) dans les méthodes de la classe, de l'interface ou de la méthode générique. L'implication est que vous pouvez convertir le type / interface / méthode en un équivalent avec un super-type deT
.Par exemple,
ICovariant<out Dog>
peut être jeté versICovariant<Animal>
.la source
out
demandes de règlement neT
peuvent être retournées que lorsque j'ai lu cette réponse. L'ensemble du concept a plus de sens maintenant!À partir du lien que vous avez publié ...
EDIT : Encore une fois, à partir du lien que vous avez publié
la source