Class versus struct
A struct is a value typeValue types and reference typesA value type variable holds the value. A reference type variable holds a reference to an object.Opens in a new tab, and a class is a reference type. Copying a struct makes an independent copy. Copying a class variable gives a second name for the same object.
struct PointStruct { public int X, Y; }class PointClass { public int X, Y; } var s1 = new PointStruct { X = 1, Y = 2 };var s2 = s1; // a copys2.X = 99; // s1.X is still 1 var c1 = new PointClass { X = 1, Y = 2 };var c2 = c1; // the same objectc2.X = 99; // c1.X is now 99 tooDifferences
Default equality compares fields for a struct, which can be slow unless Equals is overridden or the type is a record structRecordsA class for immutable data, with value-based equality generated for you.Opens in a new tab, and compares references for a class. A struct cannot inherit from a class or struct but can implement interfaces. A struct always exists with zeroed fields, where a class variable can be null. A struct cannot have a finalizer.
When a struct fits
Microsoft’s guidance: small (about 16 bytes), logically a single value, immutable, and not boxed often. Point, Coordinates and DateTime fit. A small local struct needs no heap allocation. A large one is costly to copy, and boxing one allocates.
Immutability
A mutable struct is a trap, because changes apply to a copy. readonly struct makes the compiler require read-only fields.
public readonly struct Coordinates{ public double Lat { get; } public double Lon { get; } public Coordinates(double lat, double lon) => (Lat, Lon) = (lat, lon);}Where it matters
A class is the default. A struct pays off for small immutable values created in large numbers, where avoiding the allocation reduces garbage collection work. See choosing a typeChoosing a typeClass, struct, interface, record class or record struct.Opens in a new tab.