C# 8.0 添加和增强的功能【基础篇】

.NET Core 3.x.NET Standard 2.1支持C# 8.0
一、Readonly 成员可将 readonly 修饰符应用于结构的成员 , 来限制成员为不可修改状态 。这比在C# 7.2中将 readonly 修饰符仅可应用于 struct 声明更精细 。
public struct Point{public double X { get; set; }public double Y { get; set; }public double Distance => Math.Sqrt(X * X + Y * Y);public override string ToString() =>$"({X}, {Y}) is {Distance} from the origin";}与大多数结构一样,ToString() 方法不会修改状态 。可以通过将 readonly 修饰符添加到 ToString() 的声明来对此进行限制:
public readonly override string ToString() =>// 编译器警告,因为 ToString 访问未标记为 readonly 的 Distance 属性$"({X}, {Y}) is {Distance} from the origin";// Distance 属性不会更改状态 , 因此可以通过将 readonly 修饰符添加到声明来修复此警告public readonly double Distance => Math.Sqrt(X * X + Y * Y);注意:readonly 修饰符对于只读属性是必需的 。
编译器会假设 get 访问器可以修改状态;必须显式声明 readonly
自动实现的属性是一个例外;编译器会将所有自动实现的 Getter 视为 readonly , 因此,此处无需向 X 和 Y 属性添加 readonly 修饰符 。
通过此功能 , 可以指定设计意图,使编译器可以强制执行该意图,并基于该意图进行优化 。
二、默认接口方法从 .NET Core 3.0 上的 C# 8.0 开始,可以在声明接口成员时定义实现 。最常见的方案是,可以将成员添加到已经由无数客户端发布并使用的接口 。示例:
// 先声明两个接口// 客户接口public interface ICustomer{IEnumerable<IOrder> PreviousOrders { get; }DateTime DateJoined { get; }DateTime? LastOrder { get; }string Name { get; }IDictionary<DateTime, string> Reminders { get; }// 在客户接口中加入新的方法实现public decimal ComputeLoyaltyDiscount(){DateTime TwoYearsAgo = DateTime.Now.AddYears(-2);if ((DateJoined < TwoYearsAgo) && (PreviousOrders.Count() > 10)){return 0.10m;}return 0;}}// 订单接口public interface IOrder{DateTime Purchased { get; }decimal Cost { get; }}// 测试代码// SampleCustomer:接口 ICustomer 的实现,可不实现方法 ComputeLoyaltyDiscount// SampleOrder:接口 IOrder 的实现SampleCustomer c = new SampleCustomer("customer one", new DateTime(2010, 5, 31)){Reminders ={{ new DateTime(2010, 08, 12), "childs's birthday" },{ new DateTime(1012, 11, 15), "anniversary" }}};SampleOrder o = new SampleOrder(new DateTime(2012, 6, 1), 5m);c.AddOrder(o);//添加订单o = new SampleOrder(new DateTime(2103, 7, 4), 25m);c.AddOrder(o);// 验证新增的接口方法ICustomer theCustomer = c; // 从 SampleCustomer 到 ICustomer 的强制转换Console.WriteLine($"Current discount: {theCustomer.ComputeLoyaltyDiscount()}");// 若要调用在接口中声明和实现的任何方法 , 该变量的类型必须是接口类型,即:theCustomer三、模式匹配的增强功能C# 8.0扩展了C# 7.0中的词汇表(isswitch),这样就可以在代码中的更多位置使用更多模式表达式 。
3.1 switch 表达式区别与 switch 语句:
??变量位于 switch 关键字之前;
??将 case 和 : 元素替换为 =>,更简洁、直观;
??将 default 事例替换为 _ 弃元;
??实际语句是表达式,比语句更加简洁 。
public static RGBColor FromRainbow(Rainbow colorBand) =>colorBand switch{Rainbow.Red=> new RGBColor(0xFF, 0x00, 0x00),Rainbow.Orange => new RGBColor(0xFF, 0x7F, 0x00),Rainbow.Yellow => new RGBColor(0xFF, 0xFF, 0x00),Rainbow.Green=> new RGBColor(0x00, 0xFF, 0x00),Rainbow.Blue=> new RGBColor(0x00, 0x00, 0xFF),Rainbow.Indigo => new RGBColor(0x4B, 0x00, 0x82),Rainbow.Violet => new RGBColor(0x94, 0x00, 0xD3),_=> throw new ArgumentException(message: "invalid enum value", paramName: nameof(colorBand)),};3.2 属性模式借助属性模式,可以匹配所检查的对象的属性 。
如下电子商务网站的示例 , 该网站必须根据买家地址(Address 对象的 State 属性)计算销售税 。
// Address:地址对象;salePrice:售价public static decimal ComputeSalesTax(Address location, decimal salePrice) =>location switch{{ State: "WA" } => salePrice * 0.06M,{ State: "MN" } => salePrice * 0.075M,{ State: "MI" } => salePrice * 0.05M,// other cases removed for brevity..._ => 0M};

推荐阅读