36

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

Turns R# curmudgeon-like with the complaint, "Co-variant array conversion from string[] to object[] can cause run-time exception on write operation".

Actually, this code works perfectly - the combo box is populated with the month values; what is Resharper on about, and what can I do to assuage its doubts?

If it's simply that the generic list may contain bad data, I won't worry about it - and if there ever were a problem, it would be easy enough to track down the problem.

Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
B. Clay Shannon-B. Crow Raven
  • 8,547
  • 144
  • 472
  • 862

2 Answers2

58

The method comboBoxMonth.Items.AddRange expects an object[] parameter. months.ToArray() is string[]. A cast from string[] to object[] is valid, but if the method tries to modify elements of the array, you will get run-time errors. In this case it doesn't, so you can ignore the warning.

If it annoys you, you can use ToArray<object>()

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

It will return object[] and no cast will be needed.

Jakub Lortz
  • 14,616
  • 3
  • 25
  • 39
  • 1
    What do you mean by *if a method tries to modify elements of the array*? Modifying an element already in the array shouldn't be a problem. – Yuval Itzchakov Nov 06 '15 at 06:08
  • 3
    @YuvalItzchakov: If the method tries to assign a banana to element one of an array of objects that is really an array of strings, then there will be a failure at runtime. People reasonably expect that assigning a banana into an array of objects will succeed, but it might not. – Eric Lippert Nov 06 '15 at 06:09
  • @EricLippert Yes, I do understand, and that was what I tried to convey in my answer. But I think there's ambiguity in the sentence that states that modifying existing elements would cause a run-time exception – Yuval Itzchakov Nov 06 '15 at 06:19
  • @YuvalItzchakov: Apparently I am not following your train of thought here. How is it ambiguous? – Eric Lippert Nov 06 '15 at 06:28
  • 1
    @YuvalItzchakov Runtime errors would occur if the function receiving that array would _store_ it as Object[] internally (while it's actually String[]) and would then try to replace one of the items on it by something that's not a String. Example: `Object[] arr = new String[5];` `arr[2] = 3;` is perfectly valid code, but it will crash when you run it. – Nyerguds May 23 '16 at 10:00
  • @EricLippert I think he assumed that the function would convert the received arg to a _real_ array of type `Object`. – Nyerguds May 23 '16 at 10:01
  • @Nyerguds I don't even remember what my train of thought was :X. Re-reading this now is pretty clear to me. – Yuval Itzchakov May 23 '16 at 10:22
21

An example to demonstrate the problem:

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

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

This will throw a ArrayTypeMismatchException at run-time.

R# is basically hinting you of a possible problem of the fact that you're assigning a string[] to an object[], which is completely allowed by the compiler, but may lead to a run-time exception if an object, which shares the same base class, is assigned to the array of which already points to a different type (as in my example, we actually point to a girafee array). Array co-variance is broken in the meaning that it doesn't supply you with the compile-time safety you get with generics.

Eric Lippert talks about this in 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.

Ceisc
  • 1,278
  • 12
  • 18
Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321