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

Why is Array Covariance not safe?

我正在从 this 博客和

阅读有关协变和逆变的信息

covariance on Array got me confused

现在,如果我有这个

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

为什么我在 运行 时间内出现错误?理论上obj是一个Object类型的变量,Object可以存储任何类型,因为所有的类型都继承自Objectclass。现在,当我 运行 这段代码时,我没有收到任何 运行 时间错误,谁能解释一下为什么

class baseclass
    {

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

            Console.Read();
        }
    }

这实际上是令人困惑的。

当你说 object[] objs = new string[4] {}; 时,objs 实际上是一个字符串数组 。不安全的数组协变是不安全的,因为类型系统在骗你。这就是它 不安全 的原因。你认为你的数组可以容纳一个盒装整数,但它实际上是一个字符串数组,它实际上只能容纳字符串

你的问题是"why is this not safe",然后你举例说明为什么不安全。它不安全,因为当你做一些看起来应该安全的事情时,它会在运行时崩溃。这违反了类型系统的最基本规则:变量实际上包含变量类型的值。

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

的内容

在我看来,这是 C# 和 CLR 最糟糕的特性。 C# 有这个特性,因为 CLR 有它。 CLR 拥有它是因为 Java 拥有它,而 CLR 设计者希望能够在 CLR 中实现类似于 Java 的语言。我不知道为什么 Java 有它;这是一个糟糕的主意,他们不应该这样做。

现在清楚了吗?

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

  1. 从数组中读取的任何值都可以存储在 T.

  2. 类型的容器中
  3. 从数组中读取的任何值都可以存储回 相同的 数组。

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

T[] 类型的非空引用将能够保存对 U[] 类型的任何对象的引用,其中 U 派生自 T。对于从 T 派生的任何可能的类型 U,从 U[] 读取的任何值都可以存储到类型 T 的容器中,也可以存储回相同的类型大批。如果 T 类型的容器包含对从 T 派生的对象的引用,但不是 U 类型,也不是从 U 派生的任何类型,则 U[] 将无法保存该引用。

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