【译】Welcome to C# 9.0
C# 9.0正在形成,我想分享我们对添加到该语言下个版本的一些主要功能的看法。对于每个新版本的 C#,我们努力使常见的编码方案更加清晰和简单,C# 9.0 也不例外。这次的一个特别重点是支持数据形状的简洁和不可变表示。 让我们潜入吧! 1 仅可初始化的属性对象初始化器是非常好用的。它们为类型实例化提供了一种非常灵活且可读的格式来创建对象,尤其是对于一次创建特别大的嵌套对象来说。下面是一个简单的例子: new Person { FirstName = "Scott",LastName = Hunter } 对象初始化也使用户不必编写大量构造函数,要做的就是编写一些属性! public class Person { string FirstName { get; set; } string LastName { ; } } 今天,一个很大的限制是,属性必须是可修改的,对象初始化器是这样工作的:首先调用对象的构造函数(默认为无参的构造函数),然后分配给属性设置器(property setter)。 仅可初始化属性修改了这一点!它们引入了一个 init 访问器,该访问器是set访问器的变体,只能在对象初始化期间调用: get; init; } ; init; } } 使用此声明,除了初始化外,之后任何后续赋值给 FirstName 和 LastName 属性都是一个错误。 因为init访问器只能在初始化期间访问,因此他们允许修改封闭类型中的只读字段,就像在构造函数中那样: private readonly string firstName; lastName; FirstName { get => firstName; init => firstName = (value ?? throw ArgumentNullException(nameof(FirstName))); } LastName { lastName; init => lastName = (value ?? ArgumentNullException(nameof(LastName))); } } 2 记录如果要使单个属性不可变,则仅可初始化属性非常适合。如果希望整个对象不可变且像值类型一样,则应考虑将其声明为记录: public data ; init; } } 类声明中的data关键字将其标记为记录。这赋予它几个类似价值类型的行为,我们将在下面深入探讨这些行为。一般来说,记录更被视为"值"(纯数据), 而不是作为对象。您可以通过创建新记录表示新状态来表示随时间的变化。它们不是由标识定义,而是由其内容定义。 2.1 With表达式使用不可变数据时,一种常见模式是从现有值创建新值以表示新状态。例如,如果我们更改LastName,我们会将其表示为一个新对象,该对象是旧对象的副本,但LastName不同。这种技术通常被称为非破坏性修改。记录这种特性表示的是Person在给定时间的状态。 为了适应这种编程风格,记录允许一种新的表达式——with: var otherPerson = person with{LastName=Hanselman"}; with表达式使用对象初始化器语法来说明新对象与旧对象的不同内容。您可以指定多个属性。 记录隐式定义一个受保护的"复制构造函数"-一个构造函数,它获取现有记录对象,并逐个将其字段复制到新的对象: protected Person(Person original){/* copy all the fields */}// generated with 表达式会导致调用复制构造函数,然后在上面应用对象初始化器以相应地更改属性。 如果您不喜欢生成的复制构造函数的默认行为,则可以改为定义自己的行为,该行为将由with表达式选取。 2.2 基于值的相等性所有对象都从Object继承 Equals(object)。结构将其重写为具有"基于价值的相等性",通过递归地调用Equals来比较结构的每个字段。记录也执行相同的操作。这意味着,根据其"值",两个记录对象可以彼此相等,而不必是同一对象。例如: var originalPerson = otherPerson with { LastName = " }; 现在 ReferenceEquals(person,originalPerson)?= false(这两个不是一个对象)但是Equals(person,originalPerson)?= true (他们有相同的值)。 如果您不喜欢生成的 Equals 重写的默认逐字段比较行为,则可以改为编写自己的字段比较行为。你只需要小心,你了解基于值的相等在记录中是如何工作的,特别是当涉及继承时。 除了重写Equals 外,还有 GetHashCode()。 2.3 数据成员记录绝大多数都是不可变的,只有只读初始化器可以通过with表达式进行非破坏性修改。为了针对这种常见情况进行优化,记录在声明时会更改string FirstName这类成员声明的行为。与其他类和结构声明中的隐式private字段不同,在记录中,这被视为public的、仅可初始化的自动属性的缩写!因此: public data classPerson { FirstName; LastName; } 与 string FirstName{; init;} string LastName{; init;} } 是相同的。 我们认为这有助于做出漂亮而清晰的记录声明。如果您真的需要私有字段,只需显式地添加private修饰符: string firstName;
2.4 基于位置的记录有时,对记录采用更为位置化的方法是有用的,在这种方法中,记录的内容通过构造函数参数的位置给出,并且可以通过解构函数来提取。 可以在记录中指定自己的构造函数和解构函数: LastName; public Person(string firstName, lastName) =>(FirstName,LastName)=(firstName,lastName); void Deconstruct(out lastName) =>(firstName,lastName)=(FirstName,LastName); } 上面代码可以简写为: class Person(string FirstName,1)">string LastName); 这将声明public的仅初始化的自动属性以及构造函数和解构函数,以便您可以编写: var person =new Person(","); positional construction var(f,l)= person; positional deconstruction 如果您不喜欢生成的自动属性,则可以改为定义自己的同名属性,生成的构造函数和解构函数将使用该属性。 2.5 记录的改变引发的问题想象一下,将记录对象放入字典中。再次找到它取决于 Equal 和GetHashCode。如果记录改变其状态,它也会改变它等于什么!我们可能再也找不到了!在哈希表实现中,它甚至可能损坏数据结构,因为定位基于的是"到达哈希表时"的哈希值! 虽然可以通过重写一些内部方法来改变这种默认的行为,但其工作量也是相当巨大的。 2.6 with表达式与继承class Person{string FirstName; LastName;} class Student:Person{int ID;} Person person =new Student{FirstName=GetNewId()}; otherPerson = person with{LastName="}; 在最后一行上使用with表达式时,编译器不知道person实际上包含了一个Student。而且,即使otherPerson实际上不是"Student"对象,它也不是一个正确的副本,该对象与复制的第一个对象具有相同的ID。 记录有一个隐藏的虚方法,它委托"克隆"整个对象。每个派生记录类型都重写此方法以调用该类型的复制构造函数,以及派生链上的复制构造函数直到基类记录的复制构造函数。with表达式只需调用隐藏的"克隆"方法,并将对象初始化器应用于结果。 2.7 值相等与继承与with表达式的实现类似,基于值的相等性也必须是"虚拟"的,即Student需要比较所有字段,即使比较时能够得知类型是基类型Person。这是很容易通过重写已经虚拟的Equals方法实现的。 但是,相等还有一个挑战:如果比较两种不同的Person,该怎么办?我们不能让其中一个决定是否相等:相等应该是对称的,所以无论两个对象中哪个是第一个,结果都应该是相同的。换句话说,他们必须就适用的相等达成一致! 说明问题的示例: Person person1 =new Person{FirstName=}; Person person2 = 5.2 ???and??:目前,??与?:如果分支之间不是同一类型会报错。新语法下,如果两个分支都可以转换为目标类型则是允许的: Person person = student ?? customer; Shared base type int? result = b ? 0 : null; nullable value type 6 改进协变有时,派生类中的方法返还比基类中的声明更具体的类型是很有用的。C# 9.0 允许: abstract Animal { abstract Food GetFood(); ... } Tiger : Animal { override Meat GetFood() => ...; } ? 此外,还要很多新的改进,让我们拭目以待吧。 原文链接????https://devblogs.microsoft.com/dotnet/welcome-to-c-9-0/?utm_source=vs_developer_news&utm_medium=referral (编辑:北几岛) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |