c# 9.0 语法新特性

文章介绍了C#语言的几个新特性,包括使用init关键字创建只读属性以简化不可变对象的构建,record类型用于简化数据对象的创建和比较,顶级程序简化程序入口,以及模式匹配的各种应用场景如声明模式、常量模式、解构模式等。
摘要由CSDN通过智能技术生成

一、只初始化 setter (Init Only Setters)

背景

在此之前,我们创建实体类的时候,都期望属性只读不允许从外部修改,会将属性的 setter 设为私有或者干脆不设置 setter,例如:

public class Person
{
    public string Name { get; private set; }
    // OR
    //public string Name { get; }
}

再添加一个拥有全部属性作为签名的构造方法:

...
public Person(string name)
{
    this.Name = name;
}
...

这样做虽然可以达到目的,但是带来了两个问题 1.假如属性增多,会带来工作量的成倍增加,以及不易维护 2.无法使用对象初始化器(object initializers)

var person = new Person
{
    Name = "Rwing" // Compile Error 
};

在这个情况下,init 关键字应运而生了。

语法

语法很简单,只需要将属性中的 set 关键字替换为 init 即可:

public string Name { get; init; }

复制

以上代码会被大致翻译为:

private readonly string _name;
public string Name
{
    get { return _name; }
    set { _name = value;}
}

可以看到,与 set 的区别是,init 会为背后的字段添加 readonly 关键字。 这样我们就可以去掉一堆属性的构造方法转而使用对象初始化器了,并且达到了不可变的目的。

var person = new Person
{
    Name = "Rwing"
};
// 初始化后无法再次修改
person.Name = "Foo"; // Error: Name is not settable

二、记录(record)

record 是介于类与结构体之间。

1、我们往往会创建一些简单的实体,它们仅仅拥有一些简单的属性,可能还有几个简单的方法,比如DTO等等,但是这样的简单实体往往又很有用,我们可能会遇到一些情况:

  比如想要克隆一个新的实体而不是简单的引用传递  

  比如想要简单的比较属性值是否都一致,

  比如在输出,我们希望得到内部数据结构而不是简单的甩给我们一个类型名称。

这些使用record刚好解决。

public record Person
{
    public string FirstName { get; init; }
    public string LastName { get; init; }
}

2、非破坏性变化:with

使用不可变数据(data)时,一种常见的模式是从现有的值中创建新值来表示新状态。例如,如果我们的 person 要更改他们的 LastName,我们会将其表示为一个新对象,该对象是旧对象的副本,只是有不同的 LastName。这种技巧通常被称之为非破坏性突变(non-destructive mutation)。记录(record)不是代表 person 在一段时间内的 状态,而是代表 person 在给定时间点的 状态。

为了帮助实现这种编程风格,记录(record)允许使用一种新的表达式 —— with 表达式:

var otherPerson = person with { LastName = "Hanselman" };

三、顶级程序(Top-level programs)

// old: 方式
using System;
class Program
{
    static void Main()
    {
        Console.WriteLine("Hello World!");
    }
}

// new
using System;
Console.WriteLine("Hello World!");

四、模式匹配

  • 声明模式
    • 简单声明
      object greeting = "Hello, World!";
      if (greeting is string message) //匹配加声明 (message是声明的变量)
          Console.WriteLine(message.ToLower()); 
    • Swith声明
      Shape s = new Circle();
      switch (s) //switch 匹配类型并声明
      {
          case Circle cirle:
              break;
          case Rectangle rectangle:
              break;
      }
      abstract class Shape {}
      class Circle : Shape { }
      class Rectangle : Shape { }
  • Var 模式
old:
bool IsValid(Person person)
{
    return person.Age > 20 && person.Age < 30;
}

new:
bool IsValid(Person person) //当行方法简写,匹配var age作为变量参与接下来计算
=> person.Age is var age && age > 20 && age < 30;
  • 常量模式
    1、
    object o = 20;
    if (o is 8){ }//相当于 o is i && i == 8
    2、
    double d = double.NaN;
    if (d == double.NaN) { }  //false
    if (double.IsNaN(d)) { }  //true	
    if (d is double.NaN) { }  //true
  • 对位模式
    using System.Text.RegularExpressions;
    
    class Program
    {
        static void Main()
        {
            var person = new Person { Name = "Kang", Age = 30, Gender = Gender.male };
            if(person is ("Kang", 30)) //和Deconstruct方法参数对应
            {
                Console.WriteLine("matche");
            }
            
        }
    }
    class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public Gender Gender { get; set; }
    
        // 要使用对位模式必须写这个方法
        public void Deconstruct(out string name, out int age)
        {
            // 将输出参数赋值
            name = Name;
            age = Age;
        }
    }
    enum Gender
    {
        male, female
    }
  • 解构模式
    using System.Text.RegularExpressions;
    
    class Program
    {
        static void Main()
        {
            var person = new Person { Name = "Kang", Age = 30, 
            Gender = Gender.male, Chinese=85, English=90, Match=60 };
            if(person is var (name, avg) && avg >=60 )
            {
                Console.WriteLine(name);
            }
            
        }
    }
    class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public Gender Gender { get; set; }
        public int Chinese { get; set; }
        public int English { get; set; }
        public int Match { get; set; }
    
    
    }
    enum Gender
    {
        male, female
    }
    
    static class PersonExtensions
    {
        public static void Deconstruct(this Person @this, out string name, out double avg)
        {
            name = @this.Name;
            avg = (@this.Chinese + @this.Match + @this.English) / 3D;
        }
    }
  • 弃元模式
    用法一、
    var person = new Person { Name = "Kang", Age = 30, Gender = Gender.male, Chinese=85, English=90, Match=60 };
    // 这里的下划线_就是弃元模式,我们可能用不到name。
    if(person is var (_, avg) && avg >=60 )
    {
    }
    
    用法二、
    _ = str ?? throw new Exception("str is null"); //判断str是空抛出异常
    
  • 属性模式
    示例一:
    var person = new Person { Name = "Kang", Age = 30};
    // 这就是属性模式,不用写Deconstruct()方法了
    if(person is { Name: "Kang" })
    {}  
    
    示例二:
    
    if(person is {}) // 等价于 person != null
    {}
    
    示例三:
    语法:表达式 is 类型模式 (对位模式) {属性模式} 声明模式
    if(person is Person("Kang", _) {Age: 18} converted)
    {}
    
    示例四:
    递归模式
    if(person is 
        {
            Name: { Length: 6 },
            Friend: { Name: "Tom" } friend //Friend是person类型,递归判断
        }
    ){}
  • 关系模式
    if(person is { Name: "Kang", Age: >= 18}){}
    //等价于
    if(person.Name=="Kang" && person.Age >= 18){}
  • 逻辑模式
    string s = "123";
    if(s is null or {Length : 0}){} //or作为逻辑判断,字符串为空或者长度等于0
  • 拓展模式
    常规属性匹配
    if(person is 
        {
            Friend: { Age >= 18 } 
        }
    ){}
    
    拓展模式:当对象只使用一个属性时,可以用点
    if(person.Friend.Age >=18){}
    
  • 列表模式
    int[] arr = { 1, 2, 3 };
    // 列表用[]表示,每个元素进行匹配,
    // 后面的..两个点表示这个列表后面可能有或者没有元素了
    if(arr is [>=10 and <=20, _, not 42, ..]){}
  • 分片模式
    int[] arr = {1, 2, 3};
    if( arr is [ >=10, _, not 42]){} //分别对三个数字进行判断
    
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一零壹0

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值