<输出T>与 <T>在泛型中 [英] <out T> vs <T> in Generics
问题描述
和
有什么区别?例如:
What is the difference between <out T>
and <T>
? For example:
public interface IExample<out T>
{
...
}
对比
public interface IExample<T>
{
...
}
推荐答案
泛型中的 out
关键字用于表示接口中的类型 T 是协变的.请参阅协方差和逆变详情.
The out
keyword in generics is used to denote that the type T in the interface is covariant. See Covariance and contravariance for details.
经典的例子是IEnumerable
.由于 IEnumerable
是协变的,您可以执行以下操作:
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;
如果这不是协变的,上面的第二行将失败,即使从逻辑上讲它应该可以工作,因为 string 派生自 object.在 方差之前通用接口被添加到 C# 和 VB.NET(在 .NET 4 和 VS 2010 中),这是一个编译时错误.
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.
.NET 4 之后,IEnumerable
被标记为协变,并成为 IEnumerable
.由于 IEnumerable
只使用其中的元素,并且从不添加/更改它们,因此将可枚举的字符串集合视为可枚举的对象集合是安全的,这意味着它是 协变.
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.
这不适用于像 IList
这样的类型,因为 IList
有一个 Add
方法.假设这将被允许:
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
然后你可以调用:
objects.Add(new Image()); // This should work, since IList<object> should let us add **any** object
这当然会失败 - 所以 IList
不能被标记为协变.
This would, of course, fail - so IList<T>
can't be marked covariant.
顺便说一句,还有一个用于 in
的选项 - 用于比较接口之类的东西.例如,IComparer
以相反的方式工作.如果 Bar
是 Foo
的子类,您可以将具体的 IComparer
直接用作 IComparer
>,因为IComparer
接口是逆变.
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.
这篇关于<输出T>与 <T>在泛型中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!