我在下面看到了以下用法:
Covariance and contravariance real world example
interface IGobbler<in T> {
void gobble(T t);
}
我不明白中的用法代表什么。它与 ref , out ??
有关系吗?答案 0 :(得分:5)
4.0中的in
和out
修饰符是强制执行(或更确切地说:启用)协方差和逆变的必要条件。
如果您添加in
,则只允许在内向(逆变)位置使用T
- 因此Add(T obj)
之类的内容很好,但T this[int index] {get;}
不是 ,因为这是一个向外(协变)的位置。
这对于4.0中的方差功能至关重要。如果存在差异,则ref
和out
都不可用(它们都是,因此:两者都没有。)
答案 1 :(得分:4)
忽略您对ref
和out
的了解,因为它与此上下文无关。在这种情况下,in
表示T
仅出现在函数名称的右侧(即在void gobble(T t)
等正式参数列表中)。如果它说out
,则T
只出现在函数名称的左侧(即返回值T foo(int x)
)。默认(不指定任何内容)允许T
出现在任一位置。
答案 2 :(得分:2)
在C#4.0中,Contravariance允许 例如,要转换为IComparer
<X>
IComparer<Y>
即使Y是派生的 X的类型。实现此IComparer 应该用In修饰符标记。
public interface IComparer<in T> {
public int Compare(T left, T right);
}
请看这里的例子和解释:
http://www.csharphelp.com/2010/02/c-4-0-covariance-and-contravariance-of-generics/
答案 3 :(得分:2)
in
修饰符告诉您该类型是逆变的,可以隐式转换为更窄的类型。请注意,在下面的示例中,即使gobble需要Shape
,也可以将其分配给Action<Rectangle>
,因为我们已将其声明为逆变。这是因为任何调用委托并将其传递给Rectangle的人显然也可以将Rectangle传递给一个接受Shape的方法。
使用in
和out
时有一些规则,但简而言之就是这样做。
例如:
public class Shape { }
public class Rectangle : Shape { }
public interface IGobbler<Shape>
{
void gobble(Shape shape);
}
public class Gobbler : IGobbler<Shape>
{
public void gobble(Shape r) { }
}
public static class Program
{
public static void Main()
{
var g = new Gobbler();
// notice can implictly convert to a narrower type because of the 'in' keyword
Action<Rectangle> r = g.gobble;
}
}
答案 4 :(得分:2)
进出与ref和out没有任何关系。
in关键字用于描述在接口实例中将使用T的实例。在示例中,您链接了该行
IGobbler<Donkey> dg = new QuadrupedGobbler();
创建一个可以喂驴的gobbler,尽管驴不是QuadrupledCreature,但它源于它。因此,您可以使用更专业的实例而不是基类作为参数。
out关键字的工作方式大致相同,除了用于描述产生东西而不是消耗它的东西。
在同一个例子中,行
ISpewer<Rodent> rs = new MouseSpewer();
创建一个ISpewer,在调用时会发出一个鼠标。鼠标不是啮齿动物,而是源于它,因此您可以使用生成类来生成比接口声明的更专业的实例。
注意两种情况下交换最专业的类的方式。当使用in关键字时,你使用专门的类作为接口的泛型参数,而在out的情况下,你使用基类作为泛型参数告诉编译器,尽管你创建了一个更专业的类,它应该把它当作基类来对待。
答案 5 :(得分:1)
我喜欢将其视为消费和生产,因为这些是大多数开发人员熟悉的隐喻。采用IGobbler<Cow>
的方法也可以接受IGobbler<Animal>
,因为可以吞噬(消耗)任何动物的Gobbler也可以吞食一头牛。这里的Gobbler是特定类型Animal的消费者,因此它使用in
标记。
上述情况(逆变)看似违反直觉,但从想要Gobbler<Cow>
的RestaurantOwner的角度考虑一下。如果一个Gobbler只会吞食Pigs并且RestaurantOwner试图喂他一头奶牛,它就行不通。他只能接受那些不那么挑剔的Gobblers,所以Gobbler<Animal>
或Gobbler<Herbivore>
工作正常。
另一方面,假设你有Farmer<Animal>
卖动物(拥有返回IEnumerable<Animal>
的Farm方法。)如果你有买家想要Buy(IEnumerable<Animal>)
,那么可以接受Farmer<Cow>.Farm()
,因为买方愿意购买任何生产的动物和奶牛是动物。这里的Farmer是特定类型Animal的生产者,所以它使用`out'标记。
答案 6 :(得分:0)
IN关键字告诉编译器我们只想使用T作为输入值。
不允许从IGobbler转发到IGobbler