Ran Turner
Ran Turner

Reputation: 18116

C# record - using with keyword to modify properties

I recently ran into the record keyword in C#, I'm able to create a an instance of a record and modify it both by assigning a value regularly and both by using the keyword with.

Is there any difference between the two ways, when should one use with?

public record Car{

    public Car(string name, int age){
        Name = name;
        Age = age;
    }

    public string Name;
    public int Age;
}


public static void Main()
{
    var car = new Car("Reno", 15);
    car.Name = "Honda";
    
    Console.WriteLine(car.Name);
    
    car = car with {Name = "BMW"};
    
    Console.WriteLine(car.Name);
}

Upvotes: 13

Views: 25314

Answers (2)

Guru Stron
Guru Stron

Reputation: 143078

One of the main reasons for records introduction in C# - make it easier to create immutable data models. with functionality was created to provide an easy to use syntax to create a copy of immutable instance with changed properties. So car = car with {Name = "BMW"}; actually does not modify the original instance (note that record's are reference types, unless they are declared as record struct's) but creates a new one and assigns it to the variable. The difference can easily be seen with the following code:

var car = new Car("Reno", 15);
var car2 = car;
car.Name = "Honda";
    
Console.WriteLine(car.Name);  // "Honda"
Console.WriteLine(car2.Name); // "Honda"
    
car2 = car with {Name = "BMW"};
    
Console.WriteLine(car2.Name); // "BMW" 
Console.WriteLine(car.Name);  // "Honda"

Also couple of notes:

  • it is recommended to use autoproperties instead of fields, i.e.:
public record Car
{
    public Car(string name, int age)
    {
        Name = name;
        Age = age;
    }

    public string Name { get; set; };
    public int Age { get; set; };
}
  • in case you need immutable data records provide neat syntax which automatically generates constructor and init-only properties:
public record Car(string Name, int Age);

Upvotes: 33

Sweeper
Sweeper

Reputation: 273320

They are not the same. The difference is that with creates a copy of the record. According to the proposal:

A with expression allows for "non-destructive mutation", designed to produce a copy of the receiver expression with modifications in assignments in the member_initializer_list.

[...]

First, receiver's "clone" method (specified above) is invoked and its result is converted to the receiver's type. Then, each member_initializer is processed the same way as an assignment to a field or property access of the result of the conversion.

So there is an extra step of copying the record if you use with.

See also the decompiled C# code on SharpLab. Notice the <Clone> call before setting car2.Name = "BMW", which does not happen when setting car.Name = "Honda".

Car car = new Car("Reno", 15);
car.Name = "Honda";
Console.WriteLine(car.Name);
Car car2 = car.<Clone>$();
car2.Name = "BMW";
Console.WriteLine(car2.Name);

Upvotes: 0

Related Questions