简体   繁体   English

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

[英]Why do we get ArrayTypeMismatch with ref params?

Given the scenerio: 鉴于scenerio:

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 {}

And the definition of ArrayTypeMisMatch: 而且ArrayTypeMisMatch的定义是

The exception that is thrown when an attempt is made to store an element of the wrong type within an array. 尝试在数组中存储错误类型的元素时引发的异常。

This Exception is thrown when an attemp is made to store an element of the wrong type within an array. 尝试在数组中存储错误类型的元素时,抛出此异常。 EG: 例如:

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

How does this exception occur? 这个异常是如何发生的? Why is it that we are doing a store operation when Invoking a method with a ref param? 为什么在使用ref param调用方法时我们正在进行存储操作?

The exception is also thrown when creating a ref to an array element of the wrong type. 在为错误类型的数组元素创建ref时,也会抛出异常。 This is admittedly unclear by just reading the exception text, but it is very briefly mentioned indirectly on the page you linked to: 仅仅通过阅读异常文本就可以清楚地看到这一点,但是在您链接到的页面上间接地简要地提到了它:

The following Microsoft intermediate language (MSIL) instructions throw ArrayTypeMismatchException : 以下Microsoft中间语言(MSIL)指令抛出ArrayTypeMismatchException:

ldelema ldelema

ldelema (load element address) is the instruction used to create a reference to an array element. ldelema (load element address)是用于创建对数组元素的引用的指令。

As for the why, it prevents every assignment to every ref argument from needing to do a run-time check of the type. 至于原因,它阻止每个 ref参数的每个赋值需要对类型进行运行时检查。

Why is it that we are doing a store operation when Invoking a method with a ref param? 为什么在使用ref param调用方法时我们正在进行存储操作?

Providing an array element as the argument to a ref parameter actually is a store operation, at least potentially. 提供数组元素作为ref参数的参数实际上存储操作,至少是潜在的。 (Yeah, you might not reassign it, but the compiler/runtime doesn't necessarily know that) (是的,您可能不会重新分配它,但编译器/运行时不一定知道

Imagine if your M method implementation was this: 想象一下,如果你的M方法实现是这样的:

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

If we type your covariant array as object[] to so it compiles and works: 如果我们将你的协变数组类型设置为object[] ,那么它将编译并运行:

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

It runs and replaced the first element with a new instance of B . 它运行并 新的B实例 替换第一个元素。 Of course, this is perfectly valid for an object[] array. 当然,这对于object[]数组是完全有效的。 So now if we simply change it to A[] : 所以现在我们只需将其改为A[]

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

It throws the exception before the potentially dangerous/catastrophic/dogs-are-cats/up-is-down call to M is processed. 它会在处理潜在危险/灾难性/狗是猫/向上呼叫M之前抛出异常。

Of course, remove the ref calls or ref against a local variable instead of the array element and it works perfectly fine since you're not messing around with the array contents. 当然,删除ref调用或ref局部变量而不是数组元素,它完全正常,因为你没有搞乱数组内容。

@hvd's answer is probably more correct in that it explains the underlying runtime mechanism for throwing, but at least here's a practical demonstration why it is so. @ hvd的答案可能更正确,因为它解释了投掷的底层运行时机制,但至少在这里是一个实际的演示为什么会如此。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM