C# 泛型中的 <out T> 与 <T>

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10956993/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 15:56:04  来源:igfitidea点击:

<out T> vs <T> in Generics

c#genericscovariance

提问by Cole Johnson

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

<out T>和 和有<T>什么区别?例如:

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

vs.

对比

public interface IExample<T>
{
    ...
}

采纳答案by Reed Copsey

The outkeyword in generics is used to denote that the type T in the interface is covariant. See Covariance and contravariancefor details.

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

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

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

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 interfaceswas added to C# and VB.NET (in .NET 4 with VS 2010), this was a compile time error.

如果这不是协变的,上面的第二行将失败,即使从逻辑上讲它应该可以工作,因为 string 派生自 object。前方差通用接口加入到C#和VB.NET(.NET 4的与VS 2010),这是一个编译时错误。

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.

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

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

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

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.

这当然会失败 - 所以IList<T>不能被标记为协变。

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 Baris a subclass of Foo, because the IComparer<in T>interface is contravariant.

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

回答by Brad Cunningham

From the link you posted....

从你发布的链接......

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

对于泛型类型参数,out 关键字指定类型参数是 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

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

回答by James World

"out T" means that type Tis "covariant". That restricts Tto 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>.

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

回答by Jodrell

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 Bananais a type of Fruit,

接受的函数ICovariantSkinned<Fruit>将能够接受ICovariantSkinned<Fruit>ICovariantSkinned<Bananna>因为ICovariantSkinned<T>是协变接口并且Banana是一种类型Fruit

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

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

回答by o0omycomputero0o

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

为了轻松记住inandout关键字的用法(还有协变和逆变),我们可以将继承形象化为包装:

String : Object
Bar : Foo

in/out

进出