为什么我们得到具有ref参数的ArrayTypeMismatch

本文关键字:ref 参数 ArrayTypeMismatch 我们 为什么 | 更新日期: 2023-09-27 18:00:05

给定场景:

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参数的方法时要执行存储操作?

为什么我们得到具有ref参数的ArrayTypeMismatch

当为错误类型的数组元素创建ref时,也会引发异常。不可否认,仅仅阅读异常文本就不清楚这一点,但在您链接到的页面上,它被非常简短地间接提及:

以下Microsoft中间语言(MSIL)指令引发ArrayTypeMismatchException:

ldelema

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

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

为什么我们在调用方法时要执行存储操作带有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);

它在处理对M的潜在危险/灾难性/狗是猫/上行是下行调用之前抛出异常。

当然,删除对局部变量的ref调用或ref,而不是数组元素,这样做效果非常好,因为您不会干扰数组内容。

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