c#covariant泛型参数

32 c# generics covariant

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

在c#4中,我可以做到

    public interface IFoo<out T>
    {

    }
Run Code Online (Sandbox Code Playgroud)

这有什么不同

    public interface IFoo<T>
    {

    }
Run Code Online (Sandbox Code Playgroud)

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

对不起,如果它是重复的,如果是的话,请将其关闭.

Eri*_*ert 40

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

当然.IEnumerable<T>是协变的.这意味着你可以这样做:

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

...

 IEnumerable<Giraffe> giraffes = GetABunchOfGiraffes();
 FeedAll(giraffes);
Run Code Online (Sandbox Code Playgroud)

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

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

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

class C<out T>
{
    private T t;
Run Code Online (Sandbox Code Playgroud)

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

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

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

我希望我们做到了,但我们必须接受我们给出的CLR类型系统.我希望将来我们可以更好地支持不可变类和协变类.

如果您对此功能感兴趣,请考虑阅读我关于我们如何设计和实现该功能的长篇系列.从底部开始:

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

  • 谢谢埃里克!这给了我一般的想法,我会读你的博客文章.PS:当我看到你的答案时,我希望看到一些酒店房间和被盗的钥匙,但我会带长颈鹿. (5认同)

rec*_*ive 5

这意味着如果你有这个:

class Parent { } 
class Child : Parent { }
Run Code Online (Sandbox Code Playgroud)

那么 的实例IFoo<Child>也是 的实例IFoo<Parent>


Tom*_*uλa 5

如果我们谈论通用差异:

协方差就是从操作返回给调用者的值.

逆向性它是相反的,它是关于调用者传递的值:

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

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