<输出T>与 <T>在泛型中 [英] <out T> vs <T> in Generics

查看:38
本文介绍了<输出T>与 <T>在泛型中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有什么区别?例如:

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 以相反的方式工作.如果 BarFoo 的子类,您可以将具体的 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.

这篇关于&lt;输出T&gt;与 &lt;T&gt;在泛型中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆