c#covariant泛型参数

时间:2011-06-28 14:59:17

标签: c# generics covariant

我试图理解这一点,但我没有从搜索中得到任何适当的结果。

在c#4中,我可以做到

    public interface IFoo<out T>
    {

    }

这与

有什么不同
    public interface IFoo<T>
    {

    }

我所知道的是out使通用参数协变(??)。 有人可以用一个例子解释<out T>部分的用法吗?另外,为什么只适用于接口和代理而不适用于类?

很抱歉,如果它是重复的,请将其关闭,如果是的话。

3 个答案:

答案 0 :(得分:40)

  

有人可以通过示例解释out T部分的用法吗?

不确定。 IEnumerable<T>是协变的。这意味着你可以这样做:

static void FeedAll(IEnumerable<Animal> animals) 
{
    foreach(Animal animal in animals) animal.Feed();
}

...

 IEnumerable<Giraffe> giraffes = GetABunchOfGiraffes();
 FeedAll(giraffes);

“Covariant”表示类型参数的赋值兼容性关系保留在泛型类型中。 GiraffeAnimal兼容,因此该关系会在构造的类型中保留:IEnumerable<Giraffe>IEnumerable<Animal>兼容。

  

为什么仅适用于接口和委托,而不适用于类?

类的问题是类往往具有可变字段。我们来举个例子吧。假设我们允许这样做:

class C<out T>
{
    private T t;

好的,现在在你继续之前仔细考虑这个问题。 C<T>可以在构造函数之外使用任何方法将字段t设置为默认值以外的其他方法吗?

因为它必须是类型安全的,C<T>现在可以没有将T作为参数的方法; T只能退回。那么谁设置t,他们从哪里获得他们从设置的值?

协变类类实际上只有在类不可变时才有效。我们没有一个很好的方法在C#中创建不可变的类。

我希望我们这样做,但我们必须使用我们获得的CLR类型系统。我希望将来我们可以更好地支持不可变类和协变类。

如果您对此功能感兴趣,请考虑阅读我的长篇系列文章,了解我们如何设计和实施该功能。从底部开始:

https://blogs.msdn.microsoft.com/ericlippert/tag/covariance-and-contravariance/

答案 1 :(得分:5)

如果我们谈论通用差异:

协方差是关于从操作返回给调用者的值。

Contravariance 它是相反的,它是关于调用者传递的值:

据我所知,如果类型参数仅用于输出,则可以使用out。但是,如果类型仅用于输入,则可以使用。这是方便的,因为编译器无法确定您是否能够记住哪种形式称为协方差,哪种形式称为逆变。如果您在声明类型后未明确声明它们,则可以使用隐式来获得相关的转换类型。

类中没有方差(协方差或逆变),因为即使你有一个只使用type参数输入的类(或者只用它来输出),你 无法指定in或out修饰符。只有接口和委托可以具有变体类型参数。首先,CLR不允许它。从概念的角度来看,Interfaces表示从特定角度查看对象的方式,而类更多是实际实现类型。

答案 2 :(得分:3)

这意味着如果你有这个:

class Parent { } 
class Child : Parent { }

然后IFoo<Child>的实例也是IFoo<Parent>的实例。