When Structs Go Bad
Posted: Wednesday, August 04, 2004 5:17 PM
by
bruce
Filed under: Tips
In tracking down the cause of a compilation error, I was once more reminded why I don't use structs that often. The situation was as follows:
A simple struct was defined
public struct Demo
{
public string value;
}
Variables of type Demo were now instantiated and placed into an ArrayList
ArrayList al = new ArrayList();
al.Add(new Demo);
Finally, a field within the struct was assigned a value through the ArrayList variable.
foreach (Demo d in al)
d.value = “Test”;
Building this code resulted in the compilation error "The left-hand side of an assignment must be a variable, property or indexer."
For anything but a struct, the code just described would work quite nicely. However, structs are special. The intent of a struct is to be instantiated on the stack instead of on the heap. There are (supposedly) speed reasons for doing this. For example, if you were to create a large number of structs for a short period of time, creating them on the stack means they get disposed of as soon as they go out of scope (instead of at garbage collection time, as would be the case for a class). This would be fine if .NET weren't so nice to developers.
The problem in this situation is that an ArrayList is (basically) a collection of pointers to other objects. But it is not possible to 'point' to a variable that has been instantiated on the stack. So when the struct is added to the ArrayList, it is boxed. That is, space on the heap is allocated and the values on the struct are copied. Then the pointer in the ArrayList is quite happy.
So why the compilation message? Because the C# compiler folk wanted the developer to be aware of what is happening under the covers in this particular situation. If the d.value assignment were actually performed, the entire struct would have to be copied to the stack, the assignment performed and the resulting struct reboxed. That has to potential to be a lot of work and, therefore, is something that should be explicitly requested.
So ultimately, the compiler writers have decided that, in a situation such as this, I need protection from myself. In principal, I don't mind. As I started out with, the ease (and invisibility) with which structs are boxed usually means that any memory gains are lost on the performance side. Unless you are very careful about how they are used. By complaint is that the compiler message is cyptic. There is nothing inately wrong with the assignment, other than the performance hit. So tell me than instead of making me puzzle about why a public element in a struct can't be the target of an assignment.
If you would like to receive an email when updates are made to this post, please register here