<out T> vs <T> in Generics

末鹿安然 提交于 2019-11-26 03:03:33

问题


What is the difference between <out T> and <T>? For example:

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

vs.

public interface IExample<T>
{
    ...
}

回答1:


The out keyword in generics is used to denote that the type T in the interface is covariant. See Covariance and contravariance for details.

The classic example is IEnumerable<out T>. Since IEnumerable<out T> is covariant, you're allowed to do the following:

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

The second line above would fail if this wasn't covariant, even though logically it should work, since string derives from object. Before variance in generic interfaces was added to C# and VB.NET (in .NET 4 with VS 2010), this was a compile time error.

After .NET 4, IEnumerable<T> was marked covariant, and became IEnumerable<out T>. Since IEnumerable<out T> only uses the elements within it, and never adds/changes them, it's safe for it to treat an enumerable collection of strings as an enumerable collection of objects, which means it's covariant.

This wouldn't work with a type like IList<T>, since IList<T> has an Add method. Suppose this would be allowed:

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

You could then call:

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

This would, of course, fail - so IList<T> can't be marked covariant.

There is also, btw, an option for in - which is used by things like comparison interfaces. IComparer<in T>, for example, works the opposite way. You can use a concrete IComparer<Foo> directly as an IComparer<Bar> if Bar is a subclass of Foo, because the IComparer<in T> interface is contravariant.




回答2:


For remembering easily the usage of in and out keyword (also covariance and contravariance), we can image inheritance as wrapping:

String : Object
Bar : Foo




回答3:


consider,

class Fruit {}

class Banana : Fruit {}

interface ICovariantSkinned<out T> {}

interface ISkinned<T> {}

and the functions,

void Peel(ISkinned<Fruit> skinned) { }

void Peel(ICovariantSkinned<Fruit> skinned) { }

The function that accepts ICovariantSkinned<Fruit> will be able to accept ICovariantSkinned<Fruit> or ICovariantSkinned<Bananna> because ICovariantSkinned<T> is a covariant interface and Banana is a type of Fruit,

the function that accepts ISkinned<Fruit> will only be able to accept ISkinned<Fruit>.




回答4:


"out T" means that type T is "covariant". That restricts T to appear only as a returned (outbound) value in methods of the generic class, interface or method. The implication is that you can cast the type/interface/method to an equivalent with a super-type of T.
E.g. ICovariant<out Dog> can be cast to ICovariant<Animal>.




回答5:


From the link you posted....

For generic type parameters, the out keyword specifies that the type parameter is covariant.

EDIT: Again, from the link you posted

For more information, see Covariance and Contravariance (C# and Visual Basic). http://msdn.microsoft.com/en-us/library/ee207183.aspx



来源:https://stackoverflow.com/questions/10956993/out-t-vs-t-in-generics

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!