C# 9.0 核心新特性详解:Init-only Setters、Records 与顶级语句
在 .NET 5.0 统一框架的背景下,C# 9.0 带来了一系列旨在精简代码、强化不可变性并提升开发效率的新特性。本文将详细解读 Init-only setters、Records、Top-level statements 以及增强的 Pattern matching 四大核心功能,助您快速掌握现代 C# 的最佳实践。
Init-only Setters (初始化设置器)
在 C# 9.0 之前,若要实例化具有只读属性的对象,通常必须在构造函数中通过参数赋值。虽然这样可以保证不可变性,但在使用对象初始值设定项(Object Initializers)时往往不够灵活。
C# 9.0 引入了 init 关键字,允许在对象创建期间对只读属性进行初始化赋值,且在赋值完成后即变为只读。
第1步:定义使用 Init 的属性类
目的: 创建一个包含不可变字段和可变字段的类,演示 init 的行为约束。
操作: 使用 get; init; 语法定义属性。
对比参考代码:
class Customers
{
public int CustomerId { get; }
public string CustomerName { get; set; }
public Customers(int customerId)
{
CustomerId = customerId;
}
static void Main(string[] args)
{
var customers = new Customers(1045)
{
CustomerName = "Tyson"
};
// customerid 不能设置,因为该属性是只读
customers.CustomerId = 1099;
}
}
第2步:应用 Init-only Setters 优化代码
动作: 将 CustomerId 修改为支持初始化的属性。
结果: 可以在对象初始值设定项中直接赋值,且后续无法修改。
示例代码:
class Customers
{
public int CustomerId { get; init; }
public string CustomerName { get; set; }
static void Main(string[] args)
{
var customers = new Customers()
{
CustomerId = 1045,
CustomerName = "Tyson"
};
// CS8852: 只能在对象初始值设定项中或在实例构造函数或...分配
customers.CustomerId = 1099;
}
}
Records (记录类型)
Records 是一种专为表示数据的引用类型设计的特性。它默认提供基于值的相等比较、自动生成 ToString() 方法,并支持通过 with 表达式轻松创建对象副本(Copy-on-Write),极大减少了样板代码。
第1步:传统方式处理对象状态变更
背景: 在没有 Record 时,需要手动拷贝所有属性以生成“修改后”的新对象。
示例代码:
class SalesOrder
{
public int OrderId { get; init; }
public string ProductName { get; init; }
public int Quantity { get; init; }
static void Main(string[] args)
{
SalesOrder order = new SalesOrder { OrderId = 1, ProductName = "Mobile", Quantity = 2 };
// 修改ProductName,需手动构造新对象
SalesOrder newOrder = new SalesOrder { OrderId = order.OrderId, ProductName = "Laptop", Quantity = order.Quantity };
}
}
第2步:使用 Record 简化克隆逻辑
入口: 使用 record 关键字声明类型。
动作: 利用 with 表达式创建继承原值并修改指定属性的新记录。
优势: 代码更直观,无需关心内部属性的逐个赋值。
public record SalesOrder
{
public int OrderId { get; init; }
public string ProductName { get; init; }
public int Quantity { get; init; }
static void Main(string[] args)
{
SalesOrder order = new SalesOrder { OrderId = 1, ProductName = "Mobile", Quantity = 2 };
// 使用 with 表达式创建副本并修改属性
SalesOrder newOrder = order with { ProductName = "Laptop" };
}
}
Top-level Statements (顶级语句)
为了降低入门门槛并简化控制台脚本类应用的编写,C# 9.0 允许直接在文件顶层编写执行代码,编译器会自动将其包装到隐藏的 Program.Main 方法中。这被称为脚本模式。
第1步:理解传统结构
场景: 打印一行欢迎语通常需要命名空间、类定义和 Main 方法签名。
参考代码:
using System;
namespace CSharp9
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Welcome!");
}
}
}
第2步:启用顶级语句
动作: 直接书写 Console.WriteLine。
可观察状态: 代码依然能正常编译运行,隐藏了繁重的脚手架代码。
简化代码:
using System;
Console.WriteLine("Welcome !");
如果项目严格限制不使用顶级语句,也可显式调用:
System.Console.WriteLine("Welcome !");
Pattern Matching (模式匹配) 增强
C# 9.0 扩展了模式匹配能力,新增了关系模式(Relational Patterns)和逻辑模式(Logical Patterns),使得在 switch 表达式中进行复杂条件判断更加自然。
关系模式: 支持使用
<,<=,>,>=等运算符进行大小比较。逻辑模式: 支持使用
and,or,not组合多个条件。
第1步:构建使用新模式匹配的类
入口: 在方法中使用 switch 表达式。
动作: 结合数值范围判断(如 < 1000)和逻辑分组(如 500 or 600)返回不同结果。
完整示例:
public class SalesOrder
{
public int OrderId { get; set; }
public string ProductName { get; set; }
public int Quantity { get; set; }
public int TotalCost { get; set; }
public double GetTotalCost() => TotalCost switch
{
500 or 600 => 10,
< 1000 => 10 * 1.5,
<= 10000 => 10 * 3,
_ => 10 * 5
};
}
class CSharpFeatures
{
static void Main(string[] args)
{
SalesOrder newOrderforCustomer1 = new SalesOrder() { OrderId = 1, ProductName = "Camera", Quantity = 1, TotalCost = 5000 };
newOrderforCustomer1.GetTotalCost();
SalesOrder newOrderforCustomer2 = new SalesOrder() { OrderId = 2, ProductName = "Pen", Quantity = 1, TotalCost = 500 };
newOrderforCustomer2.GetTotalCost();
}
}
总结
C# 9.0 通过上述四个核心特性,显著提升了开发人员处理数据的便利性。Init-only setters 让不可变对象的初始化更安全简洁;Records 极大地减少了数据模型的样板代码;Top-level statements 让小型脚本不再繁琐;而增强的模式匹配则让条件分支逻辑更加清晰易读。
以上就是 C# 9.0 推出的4个新特性的详细内容,更多关于 C# 语言进阶的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









