为什么要实现变型接口的类保持不变? [英] Why classes that implement variant interfaces remain invariant?

查看:169
本文介绍了为什么要实现变型接口的类保持不变?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

C#4.0扩展了合作和逆变进一步泛型类型和接口。某些接口(如的IEnumerable< T> )是协变量,所以我可以做这样的事情:

C# 4.0 has extended the co and contravariance further for generic types and interfaces. Some interfaces (like IEnumerable<T>) are covariants, so I can do things like:

IEnumerable<object> ie = new List<string>();

但对于这条线?我有一个编译时错误

but what about this line? I got a compile-time error

List<Object> list = new List<String>();
//Cannot implicitly convert type List<string>' to List<object>'

我的意思是,如果列表&LT; T&GT; 实施的IEnumerable&LT; T&GT; 为什么名单,LT ; T&GT; 仍是不变的?就是在那里,解释为什么这应该不是在C#允许一个很好的反例?

I mean, if List<T> implement IEnumerable<T> why List<T> is still invariant? Is out there a good counterexample that explain why this should not be allowed in C#?

推荐答案

首先,类的总是的不变性在C#。你不能声明一个类是这样的:

Firstly, classes are always invariant in C#. You can't declare a class like this:

// Invalid
public class Foo<out T>

二 - 更重要的是你给的例子 - 列表&LT; T&GT; 不能被宣布为协变或逆变ŧ无论如何,因为它的成员都接受和返回类型的值 T

Secondly - and more importantly for the example you've given - List<T> couldn't be declared to be covariant or contravariant in T anyway, as it has members both accepting and returning values of type T.

试想一下,如果它的的协变。然后,你可以写这个(为明显的水果类层次结构):

Imagine if it were covariant. Then you could write this (for the obvious Fruit class hierarchy):

List<Banana> bunchOfBananas = new List<Banana>();
// This would be valid if List<T> were covariant in T
List<Fruit> fruitBowl = bunchOfBananas;
fruitBowl.Add(new Apple());
Banana banana = bunchOfBananas[0];

你所期望的最后一行呢?从根本上说,你不应该能够将苹果引用添加到一个对象,其实际执行时类型列表&LT;香蕉&GT; 。如果添加一个苹果一串香蕉,它脱落。相信我,我试过。

What would you expect that last line to do? Fundamentally, you shouldn't be able to add an Apple reference to an object whose actual execution-time type is List<Banana>. If you add an apple to a bunch of bananas, it falls off. Believe me, I've tried.

最后一行的 的应该是在类型方面安全 - 一个列表与LT中唯一的值;香蕉&GT; 香蕉的实例或子类的引用。

The last line should be safe in terms of types - the only values within a List<Banana> should be null or references to instances of Banana or a subclass.

现在至于为什么类不能被协变,即使他们可能的逻辑的是...我认为,引入在执行层面的问题,也将是的非常限制性的编程水平以及。例如,考虑一下:

Now as for why classes can't be covariant even when they could logically be... I believe that introduces problems at the implementation level, and would also be very restrictive at the programming level as well. For example, consider this:

public class Foo<out T> // Imagine if this were valid
{
    private T value;

    public T Value { get { return value; } }

    public Foo(T value)
    {
        this.value = value;
    }
}

这仍可能有无效 - 变量仍是可写的,这意味着它算作一个中插槽。你必须做类型的每个变量 T ...只读,这还只是个开始。我强烈怀疑会有更深层次的问题。

That would still probably have to be invalid - the variable is still writable, meaning it counts as an "in" slot. You'd have to make every variable of type T read-only... and that's just for starters. I strongly suspect that there would be deeper problems.

在纯实用主义方面,CLR已经支持委托和接口方差V2 - C#4刚刚推出的语法揭露功能。我不相信CLR曾经支持泛型类方差。

In terms of pure pragmatism, the CLR has supported delegate and interface variance from v2 - C# 4 just introduced the syntax to expose the feature. I don't believe the CLR has ever supported generic class variance.

这篇关于为什么要实现变型接口的类保持不变?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆