C# · Intermediate

Records

Most classes in a web app just carry data: an OrderDto, a Money value, an API response. A record gives you such a type in one line, with equality and printing built in.

Advanced 5 min Lesson 23 of 26Examples target C# 13 on .NET 9 unless stated otherwise.
Before you start:Classes and Objects
0/26 in C#
On this page · 5 min · Advanced

In simple words#

A record is like an Aadhaar card printout: a fixed set of details. Two printouts with the same details are considered equal, and to “change” it you print a new copy.

record
A type for data with value equality.
Value equality
Equal if all values are equal.
with
Create a copy with some values changed.

Learning objectives#

  • Declare a positional record
  • Explain value equality vs reference equality
  • Create modified copies with with
  • Know when to use records, classes and record structs

Explanation#

record Point(int X, int Y); creates a type with two read-only (init) properties, a constructor, and more — in one line.

Records use value equality: two records are equal when all their values are equal. Two class objects are equal only if they are the same object.

ToString() is generated for you: Point { X = 2, Y = 3 }. Very handy in logs.

Records are immutable by default. To “change” one, make a copy with a with-expression: var moved = p with { X = 10 };. The original is untouched.

You can deconstruct a positional record: var (x, y) = point;. record struct makes a value-type record for small, frequently created values.

Syntax#

C# Illustrative
record Product(string Name, decimal Price);


var p1 = new Product("Pen", 20m);
var p2 = p1 with { Price = 25m };   // copy with one change
bool same = p1 == new Product("Pen", 20m);   // true

Code example: Records vs classes#

C#Program.cs Illustrative
var a = new Point(2, 3);
var b = new Point(2, 3);
Console.WriteLine(a);
Console.WriteLine(a == b);


var moved = a with { X = 10 };
Console.WriteLine(moved);
Console.WriteLine(a);


var (x, y) = moved;
Console.WriteLine(
quot;x=
{x}, y={y}");
var c1 = new PointClass(2, 3); var c2 = new PointClass(2, 3); Console.WriteLine(c1 == c2); var order = new OrderDto(1001, "Asha", 1499.50m); Console.WriteLine(order); record Point(int X, int Y); record OrderDto(int Id, string Customer, decimal Total); class PointClass(int x, int y) { public int X => x; public int Y => y; }
Expected output
Point { X = 2, Y = 3 }
True
Point { X = 10, Y = 3 }
Point { X = 2, Y = 3 }
x=10, y=3
False
OrderDto { Id = 1001, Customer = Asha, Total = 1499.50 }

This example is illustrative. Copy or download it and run it in your own environment; the expected output is shown above.

Step-by-step explanation#

  1. record Point(int X, int Y) generates properties X and Y, a constructor, equality and ToString.
  2. a == b is True because both records hold the same values.
  3. with makes a new record with X changed; a still has X = 2.
  4. var (x, y) = moved splits the record into two variables.
  5. The equivalent class compares by reference, so c1 == c2 is False.

Real-world use case#

Web API request and response DTOs (CreateProductRequest, ProductResponse), messages on a queue, and value objects such as Money(decimal Amount, string Currency) are natural records.

Common mistakes#

Using records for entities with identity

An EF Core entity that changes over time (a Customer) should be a class. Value equality makes two different customers with the same name “equal”.

Thinking records are deeply immutable

A record holding a List can still have that list modified. Use IReadOnlyList or immutable collections.

Expecting with to change the original

with always returns a new object. Assign the result.

Best practices#

  • Use records for DTOs, messages and value objects
  • Use classes for entities and services
  • Keep records small and immutable
  • Use record struct for tiny, hot-path values

Remember this#

record = data class with value equality.

with = copy with changes; the original stays the same.

Same values → == is true (for records).

Practice exercise#

Your task: Create a record Money(decimal Amount, string Currency). Create 100 INR, make a copy with Amount 250 using with, and print both plus whether new Money(100, "INR") equals the first one.

Need a hint?
Records print themselves nicely with Console.WriteLine.
Show solution
C# Illustrative
var price = new Money(100m, "INR");
var higher = price with { Amount = 250m };
Console.WriteLine(price);                           // Money { Amount = 100, Currency = INR }
Console.WriteLine(higher);                          // Money { Amount = 250, Currency = INR }
Console.WriteLine(price == new Money(100m, "INR")); // True


record Money(decimal Amount, string Currency);

Mini quiz#

Records quizPredict the output Question 1 of 3

What is printed?

var a = new Tag("csharp");
var b = new Tag("csharp");
Console.WriteLine(a == b);


record Tag(string Name);
Score so far: 0/0

Want more? Practise all C# MCQs · C# interview questions

My notes#

Saved in this browser.

Progress is saved in this browser. Sign in to sync.