Recently I was learning data types in C#, and struct
and class
seemed to be the most similar data structure. Both of them can store nested data and have functions. But digging further down, I realized they have specific implementation and usage trade-offs.
This article is a short discussion based on my findings.
Brief Introduction to types in C#
C# has a unified type system, but they can be categorized into two distinct definition - Value type and Reference type. Variables of that are value type directly store their data, but reference type only stores the reference to their data.
By default, on assignment, passing an argument to a method, and returning a method result, variable values are copied. In the case of value-type variables, the corresponding type instances are copied.
The Difference
Struct | Class |
---|---|
Value type | Reference type |
Allocated on the Stack or inline in the containing type | Allocated on Heap |
Deallocated when the Stack unwinds or when their containing type gets deallocated | Garbage Collected |
Cheaper allocations and deallocations then Class | Costly allocations and deallocations then Struct |
Boxed and Unboxed on value => reference => value type casting | No boxing or unboxing occurs |
Copy entire value on assignment | Copy only reference on assignment |
Changes to passed value doesn’t change original data | Changes to an instance of a reference type affects all reference pointing to that instance |
Can not be inherited | Can be inherited |
Which one to choose
As we can see, struct
behaves similar to a native data type. They are most suitable for storing data that are low-level and doesn’t need a complex state. Classes
are best for maintaining complex state and data hierarchy. The use of struct
is most suitable when they have all of the following characteristics -
- ✅ It logically represents a single value, similar to primitive types (
int
,double
, etc.). - ✅ It has an instance size under 16 bytes.
- ✅ It is immutable.
- ✅ It will not have to be boxed frequently.
One optimization we can achieve is by using in
, ref
, and out
parameter modifiers, a value can be passed as a reference in the parameter of a function. These keywords have specific behaviors and should be used in their correct scenario.