in modifier在参数列表中的含义是什么?

时间:2011-06-01 15:26:48

标签: c#

我在下面看到了以下用法:

Covariance and contravariance real world example

interface IGobbler<in T> {
    void gobble(T t);
}

我不明白的用法代表什么。它与 ref out ??

有关系吗?

7 个答案:

答案 0 :(得分:5)

4.0中的inout修饰符是强制执行(或更确切地说:启用)协方差和逆变的必要条件。

如果您添加in,则只允许在内向(逆变)位置使用T - 因此Add(T obj)之类的内容很好,但T this[int index] {get;} 不是 ,因为这是一个向外(协变)的位置。

这对于4.0中的方差功能至关重要。如果存在差异,则refout都不可用(它们都是,因此:两者都没有。)

答案 1 :(得分:4)

忽略您对refout的了解,因为它与此上下文无关。在这种情况下,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的方法。

使用inout时有一些规则,但简而言之就是这样做。

例如:

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