协方差和向上转换之间的区别

发布于 2024-11-24 07:08:13 字数 447 浏览 0 评论 0原文

协变和向上转换之间有什么区别,或者更具体地说,为什么它们有不同的名称?

我见过以下被称为“向上转型”的示例:

string s = "hello";
object o = s;  //upcast to 'string' to 'object'

然而,我见过以下被称为“协方差”的示例:

string[] s = new string[100];
object[] o = s;

IEnumerable<string> ies = new List<string>();
IEnumerable<object> ieo = ies;

现在,在我未经训练的眼中,协变似乎与向上转型相同,只是它指的是集合的转型。 (关于逆变和向下转型也可以做出类似的陈述)。

真的有那么简单吗?

What is the difference between covariance and upcasting, or, more specifically, why are they given different names?

I've seen the following example referred to as 'upcasting':

string s = "hello";
object o = s;  //upcast to 'string' to 'object'

Whereas, the following I have seen called 'covariance':

string[] s = new string[100];
object[] o = s;

IEnumerable<string> ies = new List<string>();
IEnumerable<object> ieo = ies;

Now, to my untrained eye, covariance seems to be the same as upcasting, except that it refers the casting of collections. (And of a similar statement can be made regarding contravariance and downcasting).

Is it really that simple?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

跨年 2024-12-01 07:08:13

现在,在我未经训练的眼中,协变似乎与向上转型相同,只不过它指的是集合的转型。 (关于逆变和向下转型也可以做出类似的陈述)。

真的那么简单吗?

协方差与向上转换无关,尽管我可以理解为什么你认为它是相关的。

协方差是关于以下非常简单的想法。假设您有一个 IEnumerable 类型的变量 衍生序列。假设您有一个 IEnumerable 类型的变量 baseSequence。这里,Derived 派生自 Base。然后,使用协变,以下是合法的赋值,并且会发生隐式引用转换:

baseSequence = derivedSequence;

请注意,这不是向上转换。 IEnumerable 并非从 IEnumerable 派生。相反,协方差允许您将变量衍生序列的值分配给变量baseSequence。这个想法是,Base 类型的变量可以从 Derived 类型的对象进行赋值,并且由于 IEnumerable 在其参数中是协变的, IEnumerable 类型的对象可以分配给 IEnumerable 类型的变量。

当然,我还没有真正解释什么是协方差。一般来说,协方差是关于以下简单的想法。假设您有一个从类型到类型的映射 F(我将用 F 表示此映射;给定类型 T 其映射 F 下的图像是 F。)假设此映射具有以下非常特殊的属性:

如果XY赋值兼容,则FF赋值兼容代码> 也是如此。

在这种情况下,我们说 F 的参数 T 是协变的。 (这里,“AB 的赋值兼容”,其中 AB 是引用类型,意味着B 的实例可以存储在 A 类型的变量中。)

在我们的例子中,C# 4.0 中的 IEnumerable 是一个隐式引用从实例转换如果 Derived 是从 Base 派生的,则将 IEnumerable 转换为 IEnumerable。赋值兼容性的方向被保留,这就是为什么我们说 IEnumerable在其类型参数中是协变的。

Now, to my untrained eye, covariance seems to be the same as upcasting, except that it refers the casting of collections. (And of a similar statement can be made regarding contravariance and downcasting).

Is it really that simple?

Covariance isn't about upcasting, although I can see why you think it's related.

Covariance is about the following very simple idea. Let's say you have a variable derivedSequence of type IEnumerable<Derived>. Let's say you have a variable baseSequence of type IEnumerable<Base>. Here, Derived derives from Base. Then, with covariance, the following is a legal assignment, and an implicit reference conversion occurs:

baseSequence = derivedSequence;

Note that this is not upcasting. It is not the case that IEnumerable<Derived> derives from IEnumerable<Base>. Rather, it is covariance that allows you to assign the value of the variable derivedSequence to the variable baseSequence. The idea is that variables of type Base can be assigned from objects of type Derived, and since IEnumerable<T> is covariant in its parameter, objects of type IEnumerable<Derived> can be assigned to variables of type IEnumerable<Base>.

Of course, I haven't yet really explained what covariance is. In general, covariance is about the following simple idea. Let's say you have a mapping F from types to types (I'll denote this mapping by F<T>; given a type T its image under the mapping F is F<T>.) Let's say that this mapping has the following very special property:

if X is assignment compatible with Y, then F<X> is assignment compatible with F<Y> as well.

In this case, we say that F is covariant in its parameter T. (Here, to say that "A is assignment compatible with B" where A and B are reference types means that instances of B can be stored in variables of type A.)

In our case, IEnumerable<T> in C# 4.0, an implicit reference conversion from instances of IEnumerable<Derived> to IEnumerable<Base> if Derived is derived from Base. The direction of assignment compatibility is preserved, and this is why we say that IEnumerable<T> is covariant in its type parameter.

回心转意 2024-12-01 07:08:13

转换是指改变对象和表达式的静态类型。

方差是指在某些情况下(例如参数、泛型和返回类型)类型的可互换性或等价性

Casting refers to changing the static type of objects and expressions.

Variance refers to the interchangeability or equivalence of types in certain situations (such as parameters, generics, and return types).

離人涙 2024-12-01 07:08:13

IEnumerable 不是从 IEnumerable派生的,因此它们之间的转换不是向上转换。 IEnumerable 的类型参数是协变的,并且字符串派生自对象,因此允许强制转换。

IEnumerable<string> is not derived from IEnumerable<object>, so the cast between them is not upcasting. IEnumerable is covariant in its type parameter and string is derived from object, so the cast is allowed.

新人笑 2024-12-01 07:08:13

它们是不同概念的原因是,与向上转型不同,协变并不总是被允许的。对于类型系统的设计者来说,将 IList 视为IList的“派生”是很容易的>,但随后我们遇到了问题:

IList<Cat> cats = new List<Cat>();
IList<Animal> animals = cats; 
animals.Add(new Dog()); //Uh oh!

如果允许的话,现在我们的 cats 列表将包含 Dog

相反,IEnumerable 接口无法添加元素,因此这是完全有效的(在 C# 4.0 中):

IList<Cat> cats = new List<Cat>();
IEnumerable<Animal> animals = cats;
//There's no way to add things to an IEnumerable<Animal>, so here we are ok

The reason they are different concepts is that, unlike upcasting, covariance is not always allowed. It would have been easy for the designers of the type-system to make IList<Cat> be considered as "derived" from IList<Animal>, but then we run into problems:

IList<Cat> cats = new List<Cat>();
IList<Animal> animals = cats; 
animals.Add(new Dog()); //Uh oh!

If this were allowed, now our cats list would contain a Dog!

In contrast, the IEnumerable<T> interface has no way of adding elements, so this is perfectly valid (in C# 4.0):

IList<Cat> cats = new List<Cat>();
IEnumerable<Animal> animals = cats;
//There's no way to add things to an IEnumerable<Animal>, so here we are ok
永言不败 2024-12-01 07:08:13

据我所知,协方差消除了在先前的向上转型之后进行显式向下转型的需要。通常,如果您向上转换对象,则只能访问基类型方法和属性,通过协变,您似乎可以通过在更多派生类声明中用更多派生类型替换更少派生类型来暗示向下转换。

From what I can gather covariance removes the need for explicit downcasting subsequent to a previous upcast. Typically if you upcast an object you can only access the base type methods and attributes, with covariance it seems you can imply the downcast by replacing lesser derived types with more derived types in the more derived class declaration.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文