<style> .reveal-up, .reveal-left, .reveal-right, .reveal-stagger > * { opacity: 1 !important; transform: none !important; } </style>
  1. Learn
  2. C#
  3. Object-oriented programming
All lessons in this course

Lesson 26 of 60 15 minIntermediate

Structs, records and value vs reference types

The two kinds of types in C#, when to write a struct, and how records give you value equality and immutability for free.

Every C# type is either a value type or a reference type. You have met both already: int and double are value types; string, arrays and classes are reference types. This lesson shows how to create your own value types (structs) and the modern records.

Interactive

struct vs class vs record

Same code, three kinds of type. Watch what p2 = p1 copies, and what == compares.

Point.cs
struct Point { public int X, Y; public Point(int x, int y) { X = x; Y = y; } } var p1 = new Point(1, 2);var p2 = p1;p2.X = 10;Console.WriteLine(p1.X);Console.WriteLine(new Point(3, 4).Equals(new Point(3, 4)));// new Point(3, 4) == new Point(3, 4)  → error CS0019
Output
1
True
Memory after line 5
stack
p1X=1 Y=2
p2X=10 Y=2
p1.X after changing p21
Equals (same values)True
== (same values)error CS0019
A struct is a VALUE type: p2 = p1 copies the whole value, so changing p2 leaves p1 alone. Equals compares the field values; == only works if you define it.

Value types vs reference types

Value typeReference type
Examplesint, double, bool, char, DateTime, enum, your structsstring, arrays, List<T>, your classes and records
Variable holdsthe data itselfa reference to the data on the heap
Assignment copiesall the dataonly the reference
Can be nullno (unless int?)yes
Default value0 / false / all fields zeronull

Structs

Point3.cs
public struct Point3{    public double X { get; }    public double Y { get; }    public double Z { get; }     public Point3(double x, double y, double z) { X = x; Y = y; Z = z; }     public double DistanceTo(Point3 o) =>        Math.Sqrt((X - o.X) * (X - o.X) + (Y - o.Y) * (Y - o.Y) + (Z - o.Z) * (Z - o.Z));     public override string ToString() => $"({X}, {Y}, {Z})";} var a = new Point3(0, 0, 0);var b = new Point3(3, 4, 12);Console.WriteLine($"{a} → {b}: {a.DistanceTo(b)}");
Output
(0, 0, 0) → (3, 4, 12): 13

Use a struct for small, simple values that are naturally copied: points, vectors, colours, coordinates, money amounts. 3D and BIM code uses structs everywhere for points and vectors, because millions of them can be stored in arrays without creating millions of heap objects.

  • Keep structs small (roughly 16 bytes or less is the usual guideline) and preferably immutable (readonly struct).
  • Structs can’t inherit from other structs or classes, but they can implement interfaces.
  • Use a class when the data is large, needs identity (“this exact beam”), or must be shared and changed in one place.

Records: data classes in one line

Records.cs
public record Section(string Name, double DepthMm, double KgPerMetre); var s1 = new Section("IPE300", 300, 42.2);var s2 = new Section("IPE300", 300, 42.2); Console.WriteLine(s1);             // readable ToString for freeConsole.WriteLine(s1 == s2);       // value equality: same data → equalvar heavier = s1 with { KgPerMetre = 49.1 };   // copy with one changeConsole.WriteLine(heavier.KgPerMetre);
Output
Section { Name = IPE300, DepthMm = 300, KgPerMetre = 42.2 }
True
49.1

That single line generates a constructor, read-only (init) properties, Equals/== based on the values, GetHashCode, a nice ToString and deconstruction. Records are ideal for data that is passed around and compared: DTOs, settings, messages, results.

Choosing

Write a…When
classobjects with identity and behaviour that change over time (a Project, a Viewport, a BankAccount)
recordimmutable data compared by value (a Section from a catalogue, an API response, a settings snapshot)
struct / readonly record structtiny values used in large numbers (Point3, Vector3, Colour)
Quick check

With struct P { public int X; }, after P a = new P(); a.X = 1; P b = a; b.X = 2;, what is a.X?

Quick check

Two separate record objects contain the same values. What does == return?

Practice

Create a record Money(decimal Amount, string Currency) and a method Money Add(Money a, Money b) that throws InvalidOperationException if the currencies differ. Add 1500 INR and 750 INR, print the result, and check equality with a new Money(2250, "INR").

Show the solution
Solution.cs
public record Money(decimal Amount, string Currency); static Money Add(Money a, Money b){    if (a.Currency != b.Currency)        throw new InvalidOperationException("Currencies differ.");    return a with { Amount = a.Amount + b.Amount };} var total = Add(new Money(1500, "INR"), new Money(750, "INR"));Console.WriteLine(total);Console.WriteLine(total == new Money(2250, "INR"));
Output
Money { Amount = 2250, Currency = INR }
True

Remember

  • Value types hold their data and are copied on assignment; reference types share one object.
  • Use small, immutable structs for simple values like points and vectors.
  • Records give value equality, ToString, with copies and immutability for free.
  • class = identity and behaviour; record = data; struct = tiny values.
0 of 60 lessons completed