With expressions

C# 9.0 .NET 5.0

Published Updated Author Jeffrey T. Fritz Reading time

With expressions let you copy immutable data and update only what changed, keeping your intent crisp and your models predictable.

With expressions arrived in C# 9.0 as part of the records story. They give you a simple way to create a new value from an existing one without mutating the original instance.

Why it matters

With expressions make immutable workflows feel natural. You can keep objects read-only by default while still evolving state in tiny, obvious steps.

Practical usage

Reach for with expressions when you model requests, commands, DTOs, or UI state snapshots. They pair especially well with records and make change intent easy to review.

Cautions

With expressions create shallow copies. If a property points to mutable reference data, both instances can still share the same underlying object unless you clone that data explicitly.

Clone and update immutable records

Use with expressions to copy a record and change only the fields that need to move forward.

Valid since C# 9.0

using System;

public record DeploymentConfig(string Service, string Region, int Replicas, bool DryRun);

public static class Program
{
    public static void Main()
    {
        var baseline = new DeploymentConfig("orders-api", "eastus", 2, DryRun: true);

        var productionPlan = baseline with
        {
            Replicas = 4,
            DryRun = false
        };

        Console.WriteLine($"Baseline:   {baseline}");
        Console.WriteLine($"Production: {productionPlan}");
    }
}

Represent state transitions without mutation

Model workflow steps as clear transitions by producing new values instead of mutating existing instances.

Valid since C# 9.0

using System;

public record TicketStatus(string Id, string Stage, string AssignedTo, DateTime UpdatedUtc);

public static class Program
{
    public static void Main()
    {
        var opened = new TicketStatus("T-1024", "Open", "unassigned", DateTime.UtcNow);
        var triaged = opened with { Stage = "Triaged", AssignedTo = "kat" };
        var inProgress = triaged with { Stage = "In Progress", UpdatedUtc = DateTime.UtcNow };

        Console.WriteLine(opened);
        Console.WriteLine(triaged);
        Console.WriteLine(inProgress);
    }
}

Learn more

with expression (Microsoft Learn)