为什么Resharper在这段代码中会提示"从string[]到object[]的协变数组转换可能会导致写操作时的运行时异常"?

37

这段代码:

comboBoxMonth.Items.AddRange(UsageRptConstsAndUtils.months.ToArray());

public static List<String> months = new List<String>
{
    "Jan",
    "Feb",
    "Mar",
    "Apr",
    "May",
    "Jun",
    "Jul",
    "Aug",
    "Sep",
    "Oct",
    "Nov",
    "Dec"
};

针对“Co-variant array conversion from string[] to object[] can cause run-time exception on write operation”的抱怨,导致R#变得像个吝啬鬼。

实际上,这段代码完美运行——组合框中填充了月份值; 那么Resharper指的是什么?我该如何缓解它的疑虑?

如果只是因为通用列表中可能包含错误数据,那我就不会担心——如果真有问题,追踪问题也很容易。


2
我猜绕过这个问题的方法是使用 List<object> 而不是 List<string> - Ron Beyer
2个回答

58

方法comboBoxMonth.Items.AddRange需要一个object[]参数。months.ToArray()string[]。从string[]object[]的转换是有效的,但如果该方法尝试修改数组元素,则会出现运行时错误。在这种情况下,它不会这样做,因此您可以忽略警告。

如果这让您感到烦恼,您可以使用ToArray<object>()

comboBoxMonth.Items.AddRange(UsageRptConstsAndUtils.months.ToArray<object>());

它将返回object[],不需要进行强制类型转换。


1
“如果一个方法试图修改数组的元素”,这句话是什么意思?修改已经存在于数组中的元素不应该成为问题。 - Yuval Itzchakov
3
如果该方法试图将香蕉分配给一个实际上是字符串数组的对象数组的元素一,则在运行时会失败。人们合理地期望将香蕉分配到对象数组中会成功,但这并不一定。 - Eric Lippert
@EricLippert 是的,我理解,并且那正是我尝试在我的回答中传达的。但是我认为在陈述修改现有元素会导致运行时异常的句子中存在歧义。 - Yuval Itzchakov
@YuvalItzchakov:显然我没有跟上你的思路。它怎么会有歧义呢? - Eric Lippert
1
如果接收该数组的函数在内部将其存储为Object[](而实际上是String[]),然后尝试用不是String的内容替换其中一个项,就会发生运行时错误。例如:Object[] arr = new String[5]; arr[2] = 3; 是完全有效的代码,但在运行时会崩溃。 - Nyerguds
显示剩余3条评论

22

一个示例以说明问题:

void Main()
{
    Animal[] animals = new Girafee[2];
    animals[0] = new Zebra();
}

public class Animal { }
public class Girafee : Animal { }
public class Zebra : Animal { }

这将在运行时引发ArrayTypeMismatchException异常。

R#基本上是在提示您可能会出现问题的情况,即您正在将string[]分配给object[],这完全由编译器允许,但如果将一个与已指向不同类型的数组相同基类的对象赋值给该数组(就像我的例子一样,我们实际上指向了girafee数组),则可能导致运行时异常。数组协变性破坏了泛型提供的编译时安全性。

Eric Lippert在Covariance and Contravariance in C#,Part Two: Array Covariance中谈到了这个问题:

不幸的是,这种特定类型的协变性是有问题的。它被添加到CLR中是因为Java需要它,而CLR设计人员希望能够支持类似Java的语言。然后我们将其添加到C#中,因为它在CLR中。当时这个决定非常有争议,我对此并不是很满意,但现在我们无能为力。

为什么这是错误的?因为总是应该将一只海龟放入动物数组中合法。使用数组协变性,您无法保证动物数组可以接受一只海龟,因为支持存储的实际上可能是一组长颈鹿。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接