3

鉴于场景:

public class Program
{
    static void Main()
    {
        object[] covarientArray= new A[] { new A() };
        object polymorphism = new A();
        object test = covarientArray[0];
        M(ref polymorphism);//fine up to here

        M(ref covarientArray[0]);//ArrayTypeMismatchException
    }

    static void M(ref object o) { Console.WriteLine(o); }
}
class A {}

以及ArrayTypeMisMatch的定义:

尝试在数组中存储错误类型的元素时引发的异常。

当尝试在数组中存储错误类型的元素时,将引发此异常。例如:

A[] invalid = new A[1];
invalid[0] = "";//I can't store a type of string within an array of type of A

这个异常是怎么发生的?为什么在调用带有ref参数的方法时我们正在执行存储操作?

4

2 回答 2

3

ref在创建错误类型的数组元素时也会引发异常。仅通过阅读异常文本显然不清楚这一点,但在您链接到的页面上间接提到了它:

以下 Microsoft 中间语言 (MSIL) 指令抛出 ArrayTypeMismatchException :

困难症

ldelema(加载元素地址)是用于创建对数组元素的引用的指令。

至于为什么,它可以防止对每个参数的每个分配都需要对类型进行运行时检查。 ref

于 2013-02-18T20:16:38.420 回答
1

为什么在调用带有 ref 参数的方法时我们正在执行存储操作?

将数组元素作为参数提供给ref参数实际上一种存储操作,至少可能是这样。(是的,您可能不会重新分配它,但编译器/运行时不一定知道

想象一下,如果您的M方法实现是这样的:

static void M(ref object o) 
{ 
    o = new B();
}

如果我们键入您的协变数组object[],那么它可以编译和工作:

object[] covariantArray= new object[] { new A() };
M(ref covariantArray[0]);
Console.WriteLine(covariantArray[0].GetType().Name); //B

它运行并用B 的新实例替换了第一个元素。当然,这对于数组是完全有效的。所以现在如果我们简单地把它改成:object[]A[]

object[] covariantArray= new A[] { new A() };
M(ref covariantArray[0]); //ArrayTypeMismatchException
Console.WriteLine(covariantArray[0].GetType().Name);

它在处理潜在危险/灾难性/dogs-are-cats/up-is-down 调用之前抛出异常M

当然,删除ref调用或ref针对局部变量而不是数组元素,它工作得非常好,因为你没有弄乱数组内容。

@hvd 的答案可能更正确,因为它解释了抛出的底层运行时机制,但至少这里有一个实际演示为什么会这样。

于 2013-02-18T20:31:37.440 回答