c# record - 使用 with 关键字修改属性

c# record - using with keyword to modify properties

我最近 运行 进入 c# 中的 record 关键字,我能够创建一个记录的实例并通过定期赋值和使用关键字来修改它with.

这两种方式有什么区别,什么时候用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);
}

它们不一样。区别在于 with 创建记录的副本。根据 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.

所以如果你使用with.

,那么多了一个复制记录的步骤

另请参阅 SharpLab 上的反编译 C# 代码。请注意设置 car2.Name = "BMW" 之前的 <Clone> 调用,这在设置 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);

在 C# 中引入记录的主要原因之一 - 更容易创建不可变 data modelswith 功能的创建是为了提供易于使用的语法来创建具有更改属性的不可变实例的副本。所以 car = car with {Name = "BMW"}; 实际上并没有修改原来的引用类型,而是创建了一个新的引用类型并将其赋值给变量。 使用下一个代码可以很容易地看出区别:

var car = new Car("Reno", 15);
var car2 = car;
car.Name = "Honda";

Console.WriteLine(car.Name);
Console.WriteLine(car2.Name);

car = car with {Name = "BMW"};

Console.WriteLine(car.Name);
Console.WriteLine(car2.Name);

还有一些注意事项:

  • 建议使用自动属性而不是字段,即:
public record Car{

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

    public string Name { get; set; };
    public int Age { get; set; };
}
  • 如果您需要不可变数据 records 提供简洁的语法,自动生成构造函数和 init-only 属性:
public record Car(string Name, int Age);