C#记录 - 使用with关键字修改属性

8

最近我在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);
}

4
使用with关键字可以创建一个全新的对象,我建议你去阅读文档。 - DavidG
2个回答

19
C#引入记录的主要原因之一是为了更容易创建不可变的数据模型。`with`功能被创建出来是为了提供一种易于使用的语法,用于创建具有更改属性的不可变实例的副本。因此,`car = car with {Name = "BMW"};`实际上并不修改原始实例(请注意,记录是引用类型,除非它们被声明为`record struct`),而是创建一个新实例并将其分配给变量。 以下代码可以很容易地看出差异:
var car = new Car("Reno", 15);
var car2 = car;
car.Name = "Honda";

Console.WriteLine(car.Name);  // "Honda"
Console.WriteLine(car2.Name); // "Honda"

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

Console.WriteLine(car.Name);  // "BMW" 
Console.WriteLine(car2.Name); // "Honda"

另外还有几点需要注意:
- 建议使用自动属性而不是字段,例如:
public record Car
{
    public Car(string name, int age)
    {
        Name = name;
        Age = age;
    }

    public string Name { get; set; };
    public int Age { get; set; };
}

如果你需要不可变的数据,record提供了简洁的语法,它会自动生成构造函数和只读属性。
public record Car(string Name, int Age);

1
太棒了!非常感谢! - undefined

0
它们不同。区别在于 with 创建记录的副本。根据 提案

with 表达式允许进行“非破坏性变异”,旨在生成带有 member_initializer_list 中分配修改的接收方表达式的副本。

[...]

首先,调用接收器的“克隆”方法(如上所述),并将其结果转换为接收器的类型。然后,每个 member_initializer 以与对字段或属性访问的赋值相同的方式进行处理,以得到转换结果。

因此,如果使用 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);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接