Reputation: 18116
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
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:
public record Car
{
public Car(string name, int age)
{
Name = name;
Age = age;
}
public string Name { get; set; };
public int Age { get; set; };
}
record
s provide neat syntax which automatically generates constructor and init-only properties:public record Car(string Name, int Age);
Upvotes: 33
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 themember_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