Records and pattern matching
Immutable value types that compare by content, plus the patterns that read them apart.
record gives you value equality, with-expressions, and deconstruction for free β then property and positional patterns let switch branch on shape.
Records are value types by content
A record is a reference type whose equality is structural, not referential. Declare one with a positional parameter list and the compiler synthesises an immutable property per parameter, plus Equals, GetHashCode, a friendly ToString, and a Deconstruct method. Two records are equal when their runtime type and every field match β no IEquatable boilerplate, no overriding ==.
record Point(int X, int Y);
Because the generated properties are init-only, a record is immutable after construction. To "change" one you make a copy.
Non-destructive mutation with with
The with expression copies a record and overrides only the members you name, leaving the original untouched. This is how you evolve immutable state: var moved = p with { Y = 9 }; produces a fresh record. The copy uses the synthesised clone, so nested unchanged fields are shared, not deep-cloned.
Deconstruction and patterns
The compiler-generated Deconstruct lets you split a record into its parts: var (x, y) = p;. The same machinery powers positional patterns in switch β (0, 0) matches the origin. Property patterns match named members instead β { X: 0 } matches any point on the Y axis. Combine them with when guards, relational patterns (> 0), and or/and to express branching logic declaratively.
Try it 5 examples
Records compare by value
C#introa == b and a.Equals(b) are both True because records compare by content, yet ReferenceEquals(a, b) is False β they are equal-by-value but distinct objects. Matching values also yield equal hash codes, and the synthesised ToString prints Point { X = 2, Y = 3 }.