我看到的在下面的用法:参数列表中的修饰符的含义是什么?
Covariance and contravariance real world example
interface IGobbler<in T> {
void gobble(T t);
}
我不明白的在代表使用。是否与编号,出?
我看到的在下面的用法:参数列表中的修饰符的含义是什么?
Covariance and contravariance real world example
interface IGobbler<in T> {
void gobble(T t);
}
我不明白的在代表使用。是否与编号,出?
忽略你对ref
和out
的了解,因为它与此上下文无关。在这种情况下,in
意味着T
只会出现在函数名称的右侧(即在形式参数列表中,如void gobble(T t)
)。如果它说out
,那么T
只会出现在函数名的左侧(即返回值如T foo(int x)
)。默认(不指定任何内容)允许T
出现在任何地方。
4.0中的in
和out
修饰符对强制执行(或者说:启用)协方差和逆变是必需的。
如果添加in
,您只能在向内(逆变)位置使用T
- 所以像Add(T obj)
是好的,但T this[int index] {get;}
不因为这是一个向外(协)的位置。
这对于4.0中的方差特征很重要。有差异的话,ref
和out
都不可用(它们都是,都是这样:都不)。
您的进出口说明很容易理解。但我仍然无法连接T和接口IGobbler
@ q0987不,这是不正确的;代表***或接口***。最值得注意的是,它现在是'IEnumerable
在'IGobbler
在C#4.0,逆变允许 例如,的IComparer
<X>
待铸造到 的IComparer<Y>
即使Y是衍生 类型X的要做到这一点的IComparer 应标明与在改性剂。
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/
的in
修饰符告诉你的类型是逆变并可以隐式转换为窄型。在下面的例子中注意到,尽管狼吞虎咽需要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;
}
}
IN关键字告诉我们只希望使用T作为输入值的编译器。
它不会允许来自比方说,IGobbler铸造IGobbler
我喜欢把它看作是消费和生产,因为这些对于大多数开发人员熟悉的隐喻。需要IGobbler<Cow>
的方法也可以接受IGobbler<Animal>
,因为可以吞噬(消耗)任何动物的狼吞虎咽也可以吞噬牛。这里的Gobbler是一种特定类型动物的消费者,所以它使用in
标签。
上述案例(反变换)看起来可能与直觉相反,但从RestaurantOwner的角度考虑,他想要一个Gobbler<Cow>
。如果一个戈布勒尔只会吞噬猪,并且该餐厅的所有者试图给他喂牛,那么它就行不通。他只能接受不那么挑剔的戈布勒,所以Gobbler<Animal>
或Gobbler<Herbivore>
工作正常。
在另一方面,假设你有一个Farmer<Animal>
出售的动物(具有返回IEnumerable<Animal>
一个农场方法。)如果你有想要Buy(IEnumerable<Animal>)
一个买方,那么它可以接受Farmer<Cow>.Farm()
,作为买方愿意购买任何生产的动物和母牛都是动物。这里的农民是特定类型动物的生产者,所以它使用'out'标签。
进出与参考和输出没有任何关系。
in关键字被用于描述在该接口的实例将消耗T的一个实例在该实例中,你链接的线
创建火鸡,可以喂驴到沉绵的驴不是一个QuadrupledCreature,但它来自它。所以你可以使用更专门的实例而不是基类作为参数。
out关键字的工作方式大致相同,只是它用于描述产生东西而不是包含它的东西。
在同一示例中,线
ISpewer<Rodent> rs = new MouseSpewer();
创建ISpewer,其调用时喷出鼠标。鼠标不是啮齿动物,而是从中派生出来的,因此您可以使用生成的类生成比接口声明的更专用的实例。
请注意在两种情况下,最特殊的类是如何交换的。当使用in关键字时,你使用专用类作为接口的通用参数,而在这种情况下,你使用基类作为通用参数来告诉编译器,尽管你创建了一个更专门的类,它应该把它当作基类来对待。
这个声明是如何工作的? IGobbler
QuadrupedGobbler实现通用的IGobbler接口,该接口通过协方差特别是接口的签名,看起来像这样'public interface IGobbler
您是否搜索过?如果搜索引擎不采用“in”这个词,你可能需要使用'+ in'而不是'in'。 – BoltClock 2011-06-01 15:28:26
ref在这方面不适用 – Jodrell 2011-06-01 15:28:41
@BoltClock,我通过使用'C#parameter ref in'或'C#in parameter'搜索谷歌并且没有有用的信息被返回。 – q0987 2011-06-01 15:42:00