Skip to content
Search lessons, topics, tests…
Esc

    ↑ ↓ moveEnter openEsc close
    Cheat sheets: all cheat sheets

    C# Records, Value Equality, and with-Expressions for Interviews

    A deep interview-ready lesson on C# records, how value equality differs from reference equality, and how with-expressions support safe nondestructive copying.

    Learning outcome

    By the end of this lesson, you should be able to explain why records exist, when they are a good fit, and how the compiler changes their behavior compared with ordinary classes and structs. You should also be able to answer interview questions about equality, hashing, immutability, inheritance, and with expressions without relying on memorized slogans.

    Intuition

    A record is a type for data. The key promise is that two instances with the same meaningful data should often be considered equal. That is different from a plain class, where equality usually means “same object in memory.” Records also make copying safer and more convenient by supporting nondestructive mutation through with expressions.

    Think of a record as a type where the data matters more than object identity. That makes records a natural fit for DTOs, messages, configuration snapshots, and small domain values. It is not a universal replacement for classes. If identity is important, such as in ORM-tracked entities, a record may be the wrong choice.

    Deep dive

    C# records come in two flavors: record class and record struct. The keyword record by itself means record class, which is a reference type. record struct is a value type. The underlying kind still matters: reference types copy references, while value types copy data.

    Records add compiler-generated members that make data modeling easier:

    For a record class, the compiler generates value-based Equals, GetHashCode, ==, !=, and a readable ToString. For a record struct, the same value-based equality exists, but the type is still a value type. That means assignment copies the data, not a shared object reference.

    The interview trap is assuming all records are immutable. They are not automatically immutable. Record class positional properties are init-only by default, which encourages immutability, but you can still add mutable members if you want. Record structs are mutable by default unless you declare them readonly.

    with expressions are another major record feature. They create a copy of an existing record and apply selected property changes to the copy. The original value remains unchanged. This is called nondestructive mutation.

    The important detail is that with does not deep clone everything. If a record contains a reference like an array or a list, the reference is copied, not the contents. That means two records can still share mutable inner objects.

    Generated equality compares instance fields, including property backing fields, using each field type's default comparer. Record-class equality also checks the equality contract. Nested references still follow their own equality semantics; matching nested content does not by itself guarantee equality.

    Failure modes

    Common mistakes interviewers like to probe:

    • Assuming a record class and a plain class behave the same for equality. They do not.
    • Assuming with mutates the original object. It creates a new one.
    • Assuming record equality performs a deep comparison of all nested objects. Nested reference members may still be compared by reference unless they override equality.
    • Using records for entities where identity is the point. That often causes confusing equality behavior in tracking and caching scenarios.
    • Forgetting that mutable members inside a record can break hash-based collections if values change after insertion.
    • Treating record struct as “just a class with nicer syntax.” It has value semantics, so copies behave differently.

    Interview drill

    1. What problem do records solve?
      • Model data with built-in value equality, concise syntax, and useful copy semantics.
    1. Is record a class or a struct?
      • record alone means record class, which is a reference type. record struct is a value type.
    1. How is equality different between a plain class and a record class?
      • A plain class usually uses reference equality. A record class uses value equality generated by the compiler.
    1. Are record structs immutable?
      • No. Positional properties are writable by default. readonly record struct makes generated positional properties init-only; objects referenced by its fields can still mutate.
    1. What does with do?
      • It creates a copy of an existing record and applies specified changes to the copy.
    1. Does with deep clone nested reference objects?
      • No. Nested references are typically copied as references.
    1. Why are records useful with dictionaries or hash sets?
      • Their generated GetHashCode and equality members make them suitable as keys when their values are stable.
    1. When should you avoid records?
      • When identity matters more than value, such as tracked entities or objects with lifecycle and mutation-heavy behavior.
    1. Can records participate in inheritance?
      • Record classes can inherit other record classes; ordinary classes cannot join that hierarchy. Record structs cannot declare a class/struct base type, but can implement interfaces.
    1. What is the biggest pitfall in an interview answer?
      • Saying “records are immutable classes.” That is incomplete and sometimes false.

    Revision checklist

    • Know the difference between reference equality and value equality.
    • Know that record means record class unless struct is specified.
    • Know that record classes generate equality members and a helpful ToString.
    • Know that with creates a copy, not a mutation.
    • Know that nested mutable members are not automatically deep-cloned.
    • Know when records are a good fit and when ordinary classes are better.

    Production code

    The example below shows a practical record for an immutable-ish money value, value equality, reference comparison, and a with expression that creates a discounted copy.

    Code walkthrough

    Money is declared as a positional record, so the compiler creates constructor parameters and properties for Amount and Currency. Because it is a record class, two separate instances with the same values compare equal.

    price1 == price2 prints True because records compare values, not object identity. ReferenceEquals(price1, price2) prints False because they are still different heap objects. The with expression produces discounted by copying price1 and replacing only Amount.

    This is the core interview takeaway: records give you value semantics on top of the underlying type kind. They are not magic immutability, and they are not a replacement for every class. They are a tool for data-centric design where equality should mean “same content.”

    Executable code examples

    Records, value equality, and with-expressions

    Program.cs

    C#Runs
    using System;
    
    var price1 = new Money(25.00m, "USD");
    var price2 = new Money(25.00m, "USD");
    var discounted = price1 with { Amount = 20.00m };
    
    Console.WriteLine(price1 == price2);
    Console.WriteLine(ReferenceEquals(price1, price2));
    Console.WriteLine(price1);
    Console.WriteLine(discounted);
    
    public record Money(decimal Amount, string Currency);

    Check the existing example

    1. Is price1 still worth 25 after constructing discounted? Yes. The new record receives 20; no assignment changes price1.Amount.
    2. Do the first two output lines disagree? No. True answers the value-equality question; False answers the object-identity question. Both can hold simultaneously.
    3. Does this sample prove that every record is deeply immutable? No. Its fields contain a decimal and a string. The nested-mutable-object warning above still applies to other record shapes.

    The last two lines use the generated ToString to display Money, Amount, and Currency; numeric formatting can depend on the current culture. This teaching type does not validate currency codes, round amounts, or implement accounting rules.

    TechInterviewNotes Editorial Team · Updated 7 Oct 2026 ·