为什么数组协方差不安全?

时间:2018-11-01 17:44:51

标签: c# covariance

我正在从this博客和

中阅读有关协方差和相反性的信息。
  

关于数组的协方差让我感到困惑

现在,如果我有这个

object[] obj= new string[5];
obj[0]=4;

为什么在运行时出现错误?理论上obj是Object类型的变量,并且Object可以存储任何类型,因为所有类型都继承自Object类。现在,当我运行此代码时,我没有遇到任何运行时错误,有人可以向我解释为什么

class baseclass
    {

    }
    class client
    {
        static void Main()
        {
            object obj = new baseclass();
            obj = 4;

            Console.Read();
        }
    }

2 个答案:

答案 0 :(得分:8)

这实际上令人困惑。

您说InputBuffer时,object[] objs = new string[4] {};实际上是一个字符串数组。不安全的数组协方差是不安全的,因为类型系统在骗你。这就是为什么它不安全的原因。您认为您的数组可以容纳一个装箱的整数,但是它实际上是一个字符串数组,除了字符串之外,它实际上什么也不能容纳。

您的问题是“为什么不安全”,然后举一个为什么不安全的例子。这是不安全的,因为当您执行看起来应该安全的操作时,它会在运行时崩溃。这违反了类型系统的最基本规则:变量实际上包含变量类型的值。

对于类型objs的变量,这不是谎言。您可以在该变量中存储任何对象,因此很安全。但是类型object的变量是一个谎言。您可以将内容存储在不是object[] 的变量中。

在我看来,这是C#和CLR最糟糕的功能。 C#具有此功能,因为CLR具有此功能。 CLR之所以拥有它,是因为Java具有它,并且CLR设计者希望能够在CLR中实现类似Java的语言。我不知道为什么Java有它。这是一个可怕的想法,他们不应该这样做。

现在清楚了吗?

答案 1 :(得分:0)

数组类型为T[]的对象具有三个显着的功能:

  1. 从数组中读取的任何值都可以存储在T类型的容器中。

  2. 从数组中读取的任何值都可以存储回 same 数组中。

  3. 适合T类型的容器的任何值都可以存储到数组中。

类型为T[]的非空引用将能够保存对类型为U[]的任何对象的引用,其中U源自T。对于从U派生的任何可能的类型T,从U[]读取的任何值都可以存储到类型T的容器中,也可以存储回相同的类型数组。如果类型为T的容器持有对从T派生但不是U类型或不是从U派生的任何类型的对象的引用,则{ {1}}将无法保存该引用。

允许代码从一个数组中读取一项并将其写回到同一数组,而又不允许它要求从一个数组中读取一项并将其写入另一个数组,这很尴尬。 C#并未尝试通过编译时约束来限制此类操作,而是选择说,如果代码尝试将U[]中保存的值存储到通过T标识的数组中,则该操作将成功如果T[]为null或标识的类型不是从T所标识的实际数组的元素类型派生的对象。