Codectionary / Developer documentation / C#

Records

Introduced in C# 9, a record is a reference type designed for immutable data, with built-in value-based equality - two records are considered equal if all their properties match, unlike classes which compare by reference. Declaring a record with positional syntax automatically generates a constructor, init-only properties, plus Equals(), GetHashCode(), ToString(), and a Deconstruct method - all boilerplate that would otherwise be written by hand.

Syntax

public record RecordName(type Prop1, type Prop2);

Examples

Basic Record

A record automatically gets a constructor, properties, value equality, and ToString.

public record Point(int X, int Y);

Point p1 = new Point(3, 4);

Console.WriteLine(p1.X);          // 3 - auto-generated property
Console.WriteLine(p1);             // Point { X = 3, Y = 4 } - auto ToString()

Point p2 = new Point(3, 4);
Console.WriteLine(p1 == p2);       // true - value equality, unlike a class
Console.WriteLine(p1.Equals(p2));   // true

Non-Destructive Mutation with with

The with expression creates a new record with some properties changed, leaving the original untouched.

public record Point(int X, int Y);

Point original = new Point(3, 4);
Point moved = original with { X = 10 };

Console.WriteLine(original);  // Point { X = 3, Y = 4 } - unchanged
Console.WriteLine(moved);      // Point { X = 10, Y = 4 }

Record with Additional Members

Records can still define their own methods alongside the automatically generated ones.

public record Rectangle(double Width, double Height)
{
    public double Area => Width * Height;
    public bool IsSquare => Width == Height;
}

Rectangle r = new Rectangle(5, 5);
Console.WriteLine(r.Area);       // 25
Console.WriteLine(r.IsSquare);    // true

Deconstruction

Records automatically support deconstruction into separate variables.

public record Point(int X, int Y);

Point p = new Point(3, 4);
var (x, y) = p;  // deconstructs automatically

Console.WriteLine($"x={x}, y={y}");

Best practices

  • Use records for simple, immutable data carriers (DTOs, value objects) instead of hand-writing a full class with Equals, GetHashCode, and ToString
  • Use the with expression to create modified copies instead of mutating a record in place, which keeps the immutability guarantees intact
  • Prefer records over classes whenever value-based equality (comparing by data, not reference) is what you actually want
  • Remember records are reference types stored on the heap like classes - "record" describes their equality/immutability behavior, not their memory location (use record struct for a value-type record)

At a glance

Purpose
Applications on the .NET platform
File extension
.cs
Runs in
.NET runtime
Usually used with
.NET SDK and libraries

Specifications & further reading

Related C# documentation

Classes & Objects
A class is a blueprint for creating objects, bundling related data (fields/properties) and behavior (methods) together. C# is a fully object-oriented language - every application has at least one class, typically with a Main method as its entry point. An object is a specific instance of a class, created with the new keyword, with its own independent copy of the class's instance data.
Constructors
A constructor is a special method that runs automatically when an object is created with new, used to initialize the object's state. A constructor shares its name with the class and has no return type. C# supports constructor overloading (multiple constructors with different parameter lists) and constructor chaining with this(...), where one constructor calls another in the same class to avoid duplicating initialization logic.
Properties (get/set)
Properties are C#'s idiomatic way to expose class data through accessor-like syntax while still allowing controlled access via get and set. Unlike a plain public field, a property can validate a value before it's set, compute a value on the fly, or restrict access to read-only. Auto-implemented properties (using { get; set; } with no body) provide a concise shorthand when no custom logic is needed.
Access Modifiers
Access modifiers control the visibility of classes, fields, methods, and properties from other parts of a program. C# provides public (accessible from anywhere), private (accessible only within the declaring class - the default for class members), protected (accessible within the class and its subclasses), internal (accessible only within the same assembly/project), and combinations like protected internal and private protected.