为什么 Resharper 会用这段代码说 "Co-variant array conversion from string[] to object[] can cause run-time exception on write operation"?

Why does Resharper say, "Co-variant array conversion from string[] to object[] can cause run-time exception on write operation" with this code?

此代码:

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"
};

抱怨使 R# 脾气暴躁,"Co-variant array conversion from string[] to object[] can cause run-time exception on write operation"。

实际上,这段代码工作得很好——组合框填充了月份值; Resharper 的用途是什么,我可以做些什么来消除它的疑虑?

如果只是通用列表可能包含错误数据,我不会担心 - 如果有问题,很容易找到问题所在。

演示问题的示例:

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[],这是编译器完全允许的,但可能会导致运行-time exception 如果共享相同基数 class 的对象被分配给已经指向不同类型的数组(如在我的示例中,我们实际上指向长颈鹿数组) .数组协方差被破坏的意思是它不能为您提供泛型所获得的编译时安全性。

Eric Lippert 在 Covariance and Contravariance in C#, Part Two: Array Covariance 中谈到了这一点:

Unfortunately, this particular kind of covariance is broken. It was added to the CLR because Java requires it and the CLR designers wanted to be able to support Java-like languages. We then up and added it to C# because it was in the CLR. This decision was quite controversial at the time and I am not very happy about it, but there’s nothing we can do about it now.

Why is this broken? Because it should always be legal to put a Turtle into an array of Animals. With array covariance in the language and runtime you cannot guarantee that an array of Animals can accept a Turtle because the backing store might actually be an array of Giraffes.

方法 comboBoxMonth.Items.AddRange 需要一个 object[] 参数。 months.ToArray()string[]。从 string[]object[] 的转换是有效的,但是如果该方法试图修改数组的元素,您将得到 运行 次错误。在这种情况下它不会,所以你可以忽略警告。

如果嫌麻烦,可以用ToArray<object>()

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

它将 return object[] 并且不需要转换。