The with expression in C# 9.0 and later

I’ve not had cause to use this so far. Which seems strange (in a way) as I used similar language features with the spread operator and changing values in TypeScript a lot.

The with expression basically copies a record, struct or anonymous type and allows us to change some values, hence creating a new instance but overriding certain properties or fields.

Note: In C# 9.0 the with expression only worked with record types, in C# 10 it can be used, additionally, with struct and anonymous types.

Let’s look at a simple example. We have my old favourite demo type, a Person record which looks like this

public record Person(string Name, int Age);

Now we’ll create a Person like this

Person scooby = new("Scooby Doo", 7);

Console.WriteLine(scooby);

This would ofcouse output something like Person { Name = Scooby Doo, Age = 7 }.

Note: Obviously this is a rather simplistic record but it should give you the idea how things work. For more complex cases imagine there’s a first name, last name, lines of an address, national insurance/social security number etc. just to make it a little more work to create copies of a Person record instance.

Now let’s say we wanted to create a new record which has all the same properties/fields bar some properties/fields that will be changed. Ofcourse we could just create a new Person in the same way as above and change the properties. However, the with expression allows us to copy and change in a more elegant way (well more elegant if we had lots more properties/fields on the record than this example).

We can write

Person scooby = new("Scooby Doo", 7);
Person scrappy = scooby with { Name = "Scrappy Doo" };

Console.WriteLine(scooby);
Console.WriteLine(scrappy);

The scooby instance remains unchanged as we’ve essentially created a new instance of the Person record, copying the Age and explicitly changing the Name.

Now, what if we wanted to simply create a new instance of a Person with the same properties and fields as the scooby instance? We can just use the { } syntax like this

Person scoobyCopy = scooby with { };

Assert.IsFalse(Object.ReferenceEquals(scooby, scoobyCopy));

As the Assert states, scooby and scoobyCopy instances are not the same instance, they are copies.

Note: If using a struct (or if you’re explicitly supplying properties for a record) as the left-hand of the with expression and change values within the curly braces, you will need properties to have setters.