232

<out T>和 和有什么不一样<T>?例如:

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

对比

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

5 回答 5

246

泛型中的out关键字用于表示接口中的类型 T 是协变的。有关详细信息,请参阅协变和逆变

经典的例子是IEnumerable<out T>。由于IEnumerable<out T>是协变的,因此您可以执行以下操作:

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

如果这不是协变的,那么上面的第二行将失败,即使在逻辑上它应该工作,因为 string 派生自 object。在将泛型接口的差异添加到 C# 和 VB.NET(在带有 VS 2010 的 .NET 4 中)之前,这是一个编译时错误。

在 .NET 4 之后,IEnumerable<T>被标记为协变,并成为IEnumerable<out T>. 由于IEnumerable<out T>只使用其中的元素,并且从不添加/更改它们,因此将可枚举的字符串集合视为可枚举的对象集合是安全的,这意味着它是covariant

这不适用于像这样的类型IList<T>,因为IList<T>有一个Add方法。假设这是允许的:

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<T>不能标记为协变。

顺便说一句,还有一个选项in- 用于比较接口之类的东西。 IComparer<in T>,例如,以相反的方式工作。您可以直接使用具体IComparer<Foo>作为IComparer<Bar>ifBar的子类Foo,因为IComparer<in T>接口是逆变的。

于 2012-06-08T23:11:15.947 回答
77

为了容易记住inandout关键字的用法(也是协变和逆变),我们可以将继承想象成包装:

String : Object
Bar : Foo

进出

于 2015-01-09T09:39:28.637 回答
60

考虑,

class Fruit {}

class Banana : Fruit {}

interface ICovariantSkinned<out T> {}

interface ISkinned<T> {}

和功能,

void Peel(ISkinned<Fruit> skinned) { }

void Peel(ICovariantSkinned<Fruit> skinned) { }

接受的函数ICovariantSkinned<Fruit>将能够接受ICovariantSkinned<Fruit>ICovariantSkinned<Banana>因为ICovariantSkinned<T>是协变接口并且BananaFruit,

接受的函数ISkinned<Fruit>只能接受ISkinned<Fruit>

于 2013-12-18T14:34:28.650 回答
50

out T”表示类型T是“协变的”。这限制T在泛型类、接口或方法的方法中仅作为返回(出站)值出现。这意味着您可以将类型/接口/方法转换为具有T.
例如ICovariant<out Dog>可以强制转换为ICovariant<Animal>.

于 2012-06-08T23:16:06.530 回答
7

从您发布的链接中......

对于泛型类型参数,out 关键字指定类型参数是 covariant

编辑:再次,从您发布的链接

有关详细信息,请参阅协变和逆变(C# 和 Visual Basic)。http://msdn.microsoft.com/en-us/library/ee207183.aspx

于 2012-06-08T23:11:02.233 回答