<out T>
和 <T>
有什么区别?例如:
public interface IExample<out T>
{
...
}
对比。
public interface IExample<T>
{
...
}
<out T>
和 <T>
有什么区别?例如:
public interface IExample<out T>
{
...
}
对比。
public interface IExample<T>
{
...
}
out
关键字用于表示接口中的类型T是协变的。有关详细信息,请参见协变和逆变性。IEnumerable<out T>
。由于IEnumerable<out T>
是协变的,您可以执行以下操作:IEnumerable<string> strings = new List<string>();
IEnumerable<object> objects = strings;
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(7); // This should work, since IList<object> should let us add **any** object
IList<T>
不能被标记为协变。in
的选项 - 这个选项被用于比较接口之类的东西。例如,IComparer<in T>
的工作方式相反。如果 Bar
是 Foo
的子类,那么你可以直接将具体的 IComparer<Foo>
用作 IComparer<Bar>
,因为 IComparer<in T>
接口是逆变的。Image
是一个抽象类,你可以使用new List<object>() { Image.FromFile("test.jpg") };
或者new List<object>() { new Bitmap("test.jpg") };
来创建一个对象列表,但是使用new Image()
是不被允许的。需要注意的是,即使使用var img = new Image();
也是不被允许的。 - Reed CopseyIList<object>
是一个奇怪的例子,如果你只是想要获取 object
类型的元素,就不需要使用泛型。 - Jodrellin
和out
关键字(以及协变性和逆变性),我们可以将继承想象成包装:String : Object
Bar : Foo
string
)应该比其基类型(object
)“更大”,因为它应该有更多的成员。因此,如果您只交换类型,则图像有效。 - Luke Vo请考虑,
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>
是一个协变接口,而Banana
是Fruit
的一种类型。
接受ISkinned<Fruit>
的函数只能接受ISkinned<Fruit>
。
out T
" 表示类型 T
是“协变”的。这限制了 T
只能出现在泛型类、接口或方法的返回值(出站)中。这意味着您可以将类型/接口/方法转换为具有 T
超类型的等效项。ICovariant<out Dog>
可以被转换为 ICovariant<Animal>
。out
约束了只能返回类型为 T
的内容。现在整个概念更加清晰易懂了! - MarioDS根据您发布的链接,对于泛型类型参数,out关键字指定类型参数是协变的。
编辑: 同样来自您发布的链接
有关更多信息,请参阅协变性和逆变性 (C# 和 Visual Basic) 。 http://msdn.microsoft.com/en-us/library/ee207183.aspx
我找到的最简单的解释在这篇文章中提到:
接口
ISomeName<in T>
- 意味着T只能作为方法的参数传递(它进入接口的方法,所以它进入内部,也许这就是我们在这里使用“in”关键字的原因...嗯,不,那只是巧合吧?)接口
ISomeName<out T>
- 意味着T只能作为方法结果返回(它是我们从方法中接收到的,所以它从中出来了 - 哇,听起来又很正常!)
//I need a fruit farm(base class) so i can produce fruits(base type)
//But what I have is an apple farm(derived class) that produce apples (derive type)
IProducer<Apple> appleFarm = new AppleProducer();
//thats ok, I'll just mark it as covariant(out) since apple is also a fruit
IProducer<Fruit> fruitFarm = appleFarm;
Apple apple = appleFarm.Produce();
//I can produce fruits since apple is a fruit
Fruit fruit = apple;
//I need an apple bakery(derive class) so i can use my apples(derive type)
//But what I have is a fruit bakery(base class) that uses fruits(base type)
IConsumer<Fruit> fruitBakery = new FruitConsumer();
//thats ok, I'll just mark it as contravariant(in) since a fruit bakery can also consume apples
IConsumer<Apple> appleBakery = fruitBakery;
//can consume apples and any fruits
appleBakery.Consume(new Apple());
fruitBakery.Consume(new Fruit());
fruitBakery.Consume(new Apple());
IProducer<Apple> appleFarm = new AppleProducer();
IProducer<Fruit> fruitFarm = appleFarm;
Apple apple = appleFarm.Produce();
Fruit fruit = apple;
IConsumer<Fruit> fruitBakery = new FruitConsumer();
IConsumer<Apple> appleBakery = fruitBakery;
fruitBakery.Consume(new Apple());
fruitBakery.Consume(new Fruit());
appleBakery.Consume(new Apple());
public interface IProducer<out T>
{
T Produce();
}
public class Fruit { }
public class Apple : Fruit { }
public class FruitProducer : IProducer<Fruit>
{
public Fruit Produce() => new Fruit();
}
public class AppleProducer : IProducer<Apple>
{
public Apple Produce() => new Apple();
}
public interface IConsumer<in T>
{
void Consume(T item);
}
public class FruitConsumer : IConsumer<Fruit>
{
public void Consume(Fruit item)
{
// Consume the fruit
}
}
public class AppleConsumer : IConsumer<Apple>
{
public void Consume(Apple item)
{
// Consume the apple
}
}