C# 9.0
with
关键字有助于 从现有记录创建新记录。
我的问题是:什么技术原因促使或可能促使使用新的关键字和语法引入此特定功能,而不是仅仅生成带有命名参数的新函数。
例如,考虑文档中的示例:
Person person1 = new("Nancy", "Davolio") { PhoneNumbers = new string[1] };
Person person2 = person1 with { FirstName = "John" };
相反,我们可以有类似的东西:
var person1 = new Person("Nancy", "Davolio", new string[1]);
var person2 = person1.With(FirstName:"John");
我认为向 C# 等广泛使用的语言添加新语法是经过仔细考虑的,并且可能在某处记录了它。
您将如何实现这个
With
方法?我们来尝试一下:
public Person With(string firstName = null, string lastName = null,
string[] phoneNumbers = null)
{
return new (
firstName ?? this.FirstName,
lastName ?? this.LastName,
phoneNumbers ?? this.PhoneNumbers
);
}
这种方法的问题是我们无法像
那样将字段设置为空Person person2 = person1 with { phoneNumbers = null };
因此需要另一种方法。我们可以添加每个可能的参数组合的重载
public Person With(string firstName);
public Person With(string lastName);
public Person With(string[] phoneNumbers);
public Person With(string firstName, string lastName);
public Person With(string firstName, string[] phoneNumbers);
public Person With(string lastName, string[] phoneNumbers);
public Person With(string firstName, string lastName, string[] phoneNumbers);
问题在于,所需重载的数量随着参数数量呈指数增长:
2n - 1.
另一种方法是让编译器处理像
person1.With(FirstName:"John")
这样的调用。它将是编译器生成的代码的语法糖。这引入了其他问题:
与非破坏性突变实施相关的一些有趣链接(
with
关键字):
最初是用
With
方法提出的。
为了从另一个对象实例默认参数值,提出了一个复杂的新语言功能:调用者-接收者参数
新设计保留了旧设计的便利性,但编译器实现起来更加简单。