7

Ok, let's have some code:

//I complie nicely
ValueType[] good = new ValueType[1];
good[0].Name = "Robin";

//I don't compile: Cannot modify expression because its not a variable
IList<ValueType> bad = new ValueType[1];
bad[0].Name = "Jerome";

struct ValueType
{
    public string Name;
}

What precisely is going on behind the scenes that is causing the compiler to baulk?

//Adding to watch the following
good.GetType().Name //Value = "ValueType[]" It's a ValueType array.
bad.GetType().Name  //Value = "ValueType[]" Also a ValueType array.

The compiler is stopping me from modifying a member of the copy of the object I want to change. But why is a copy being made from this array?

A little more research throws up:

var guess = (ValueType[]) bad;
guess[0].Name="Delilah";

Now, what do you think bad[0].Name is? That's right, it's "Delilah".

Robino
  • 4,530
  • 3
  • 37
  • 40
  • 1
    The compiler is being generous, it's stopping your from modifying a copy of `Name`. Look at [Modify Struct variable in a Dictionary](http://stackoverflow.com/questions/6255305/modify-struct-variable-in-a-dictionary) – Yuval Itzchakov Sep 26 '14 at 13:30
  • @YuvalItzchakov yes it's being very helpful. Why is it copied in the second case but not the first? – Robino Sep 26 '14 at 13:31
  • The qn you linked to I had already upvoted. It does, however, very obviously make a copy of the value type. In my example it feels somewhat more subtle. – Robino Sep 26 '14 at 13:33
  • 2
    http://social.msdn.microsoft.com/Forums/en-US/5d02fe6b-8801-4bfd-b9b4-49a17de87beb/array-of-structs-array-element-access?forum=csharplanguage is also relevant – Tejas Sharma Sep 26 '14 at 13:37
  • Because the array being a compile time known type will cause a side-effect in the array value itself, not in a copy of the value. – Yuval Itzchakov Sep 26 '14 at 13:38
  • @TejasSharma the link is highly relevant. But it talks about the difference between `var good = ValueType[1]` and `var bad = List`. – Robino Sep 26 '14 at 13:47
  • it's relevant because it explains that a copy of the struct is not made when accessed through the indexer of an array as opposed to when it's accessed via the indexer of a list (which is why your program doesn't compile when you use a list) – Tejas Sharma Sep 26 '14 at 13:49
  • @TejasSharma as you see from my code, I never use a List. The GetType is an array for both cases. – Robino Sep 26 '14 at 13:55
  • `IList`. That's what the compiler knows about your variable. It has no way of "deducing" the run time type of `bad`. dasblinkenlight's answer is pretty spot on. – Tejas Sharma Sep 26 '14 at 14:16
  • You mean compile time, right?> – Robino Sep 26 '14 at 14:16

1 Answers1

7

Why is a value type being copy-returned from the IList<ValueType> but not from the array

Because an array is a built-in construct known to the compiler. Its operator [] has a built-in semantic, which provides the compiler with a modifiable reference inside the array itself.

When the compiler deals with an interface, on the other hand, all it knows it that it gets back a copy of a value type, which you are trying to modify. In other words, the compiler views IList's operator [] and array's operator [] differently.

Note: it goes without saying that this exercise is of purely academic value, because mutable structs are evil.

Community
  • 1
  • 1
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523