I’ve never been a big fan of using structs instead of classes in C#. I always thought, “If JavaScript, Python, and Groovy don’t need them, why should I?” They seem to exist mainly, if not solely, for performance optimization, which I probably wouldn’t need to worry about most of the time.
However, the introduction of ValueTuples in C# 7, which make working with multiple return values a breeze, has made me reconsider structs. One key performance advantage is that structs don’t have the Object header present in all reference types (class instances). This header takes up 8 bytes on 32-bit systems and 16 bytes on 64-bit systems. This can be a significant saving when dealing with many instances of a class or struct, as explained in huge difference.. Additionally, I’ve read that assignments and modifications can be a bit tricky with structs. After some research and testing, here’s a short overview. Most of the essentials are covered in This entry in MSDN.
Structs are value types. When you create a struct, the variable assigned to it holds the struct’s data directly. Assigning the struct to another variable creates a copy. Therefore, the original and new variables each hold independent copies, and changes to one don’t affect the other.
Value-type variables directly store their values, meaning the memory is allocated inline wherever the variable is declared. This means there’s no additional heap allocation or garbage collection overhead for value-type variables.
Heap vs Stack. Declaring a struct variable creates the struct on the stack: var myStruct = new MyStruct();. However, when a class has a struct as a field or property, the struct resides in the heap. Unlike a reference to a separate memory location, the field directly embeds the struct’s data.
Because structs are either on the stack or inlined, assignments are based on copying. Whether assigning a local struct variable, a struct field/property, or passing it as a parameter, the struct is copied. Here are some examples:
| |
Modifying a struct through a field versus a property presents a crucial difference. With a struct field, direct modification is allowed: instance.structField.field = value;.
| |
| |
However, doing the same with a struct property (instance.structProperty.field = value;) results in a compilation error.
| |
This error makes sense because accessing the property returns a copy, not a reference, so the attempted modification is invalid.
Finally, assigning either a struct property or field to a variable creates a modifiable copy of the original struct.