<out T>
和之间有什么区别<T>
?例如:
public interface IExample<out T>
{
...
}
与
public interface IExample<T>
{
...
}
<out T>
和之间有什么区别<T>
?例如:
public interface IExample<out T>
{
...
}
与
public interface IExample<T>
{
...
}
Answers:
out
泛型中的关键字用于表示接口中的类型T是协变的。有关详细信息,请参见协方差和协方差。
典型的例子是IEnumerable<out T>
。由于IEnumerable<out T>
是协变的,因此您可以执行以下操作:
IEnumerable<string> strings = new List<string>();
IEnumerable<object> objects = strings;
如果这不是协变的,则上面的第二行将失败,即使从逻辑上讲它应该可以工作,因为字符串是从对象派生的。前方差通用接口加入到C#和VB.NET(.NET 4的与VS 2010),这是一个编译时错误。
.NET 4之后,IEnumerable<T>
被标记为协变,并成为IEnumerable<out T>
。由于IEnumerable<out T>
仅使用其中的元素,并且从不添加/更改它们,因此将字符串的可枚举集合视为对象的枚举是安全的,这意味着它是协变的。
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>
if Bar
是其的子类。Foo
IComparer<in T>
Image
是抽象类;)您可以毫无问题地进行操作new List<object>() { Image.FromFile("test.jpg") };
,也可以这样做new List<object>() { new Bitmap("test.jpg") };
。您的问题new Image()
是不允许的(您也不能这样做var img = new Image();
)
IList<object>
是一个奇怪的示例,如果需要,则object
不需要泛型。
考虑,
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<Bananna>
因为ICovariantSkinned<T>
是协变接口并且Banana
是的类型Fruit
,
接受的功能ISkinned<Fruit>
将只能接受ISkinned<Fruit>
。
“ out T
”表示类型T
为“协变”。这就限制T
了它只能在通用类,接口或方法的方法中显示为返回(出站)值。这意味着您可以将类型/接口/方法转换为具有的超类型的等效项T
。
例如,ICovariant<out Dog>
可以强制转换为ICovariant<Animal>
。
out
强制T
返回的强制执行。整个概念现在变得更有意义!
从您发布的链接...。
对于泛型类型参数,out关键字指定类型参数为covariant。
编辑:再次,从您发布的链接
有关更多信息,请参见协方差和协方差(C#和Visual Basic)。http://msdn.microsoft.com/en-us/library/ee207183.aspx