为什么我们使用ref params得到ArrayTypeMismatch?

时间:2013-02-18 20:10:23

标签: c#

鉴于场景:

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:

的定义
  

尝试存储时抛出的异常   数组中错误类型的元素。

当尝试存储数组中错误类型的元素时,抛出此异常。 E.G:

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

这种异常是如何发生的?为什么在调用带有ref param的方法时,我们正在进行存储操作?

2 个答案:

答案 0 :(得分:3)

在为错误类型的数组元素创建ref时也会抛出异常。仅仅通过阅读异常文本就可以清楚地看到这一点,但是在您链接到的页面上间接地简要地提到了它:

  

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

     

ldelema

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

至于原因,它阻止 每个 ref参数的每个赋值都需要对类型进行运行时检查。

答案 1 :(得分:1)

  

为什么在调用方法时我们正在进行存储操作   用ref param?

提供一个数组元素作为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);

它会在处理M潜在危险/灾难性/狗 - 猫/上下呼叫之前抛出异常。

当然,针对局部变量而不是数组元素移除ref调用或ref,因为您没有弄乱数组内容,所以它可以正常工作。

@ hvd的答案可能更正确,因为它解释了投掷的基本运行时机制,但至少在这里是一个实际的演示为什么会这样。