可空的引用类型(C#8)
1、复习:C#数据类型分为值类型和引用类型两种,值类型的变量不可以为空,而引用类型变量可以为空
2、问题:如果不注意检查引用类型变量是否可空,就有可能造成程序中出现NullReferceException异常
3、csproj中<Nullable>enable</Nullable>启用可空引用类型检查,默认是启用的,建议启用
4、在引用类型后加“?”修饰符来声明这个类型时可空的。对于没有添加“?”修饰符的引用类型的变量,如果编译器发现存在为这个变量赋值null的可能性的时候,编译器会给出警告信息
有警告的声明
消除警告(加上?)
有警告的代码
消除警告的代码
使用!来抑制警告
如果程序员确认被访问的变量、成员确实不会出现为空的情况,也可以在访问可空的变量、成员的时候加上!来抑制编译器的警告。不要滥用
Student s1 = GetData();
Console.WriteLine(s1.Name.ToLower());
Console.WriteLine(s1.PhoneNumber!.ToLower());
记录(record)类型(C#9)
1、C#中的==运算符默认是判断两个变量指向的是否是同一个对象,即使两个对象内容完全一样,也不相等。可以通过重写Equals方法、重写==运算符等来解决这个问题,不过需要开发人员编写非常多的额外代码。
2、在C#9.0中增加记录(record)类型的语法、编译器会为我们自动生成Equals、GetHashcode等方法。
public record Person(string FirstName, string LastName);
输入以下代码,发现==和ToString已经被重写
Person p1 = new Person("Yang", "Zack");
Person p2 = new Person("Yang","Zack");
Person p3 = new Person("Gates", "Bill");
Console.WriteLine(p1.ToString);//Person{id = ?,Name = ?,Age = ?}
Console.WriteLine(p1==p2);//False
Console.WriteLine(p1==p3);//True
record的的原理及深入
原理探究
- 编译器会根据Person类型中的属性定义,自动为Person类型生成包含全部属性的构造方法。注意,默认情况下,编译器会生成已给包含所有属性的构造方法,因此,我们编写new Person()、new Person("Yang")这两种写法都是不可以的。也会生成ToString方法和Equals等方法。
- 通过反编译看背后原理。避免反编译的优化,需要把反编译器生成的代码改成C#8.0的语法。结论:record就是普通的一个类。
- record数据类型为我们提供了为所有属性赋值的构造方法,所以有属性都是只读的,而且对象可以进行值相等性比较,并且提供了可读性强的ToString()返回值。在需要编写一些不可变类并且需要进行对象,record可以帮助我们把代码的编写难度大大降低
record深入
- 可以实现部分属性是只读的、而部分属性是可以读写。
- 默认生成的构造方法的行为不能修改,我们可以为类型提供多个构造方法,然后其他构造方法通过this调用默认的构造方法
- 也推荐使用只读属性的类型。这样的所有属性都为只读的类型叫做“不可变类型”,可以让程序逻辑简单,减少并发访问、状态管理等的麻烦。
对象的副本
1、record也是普通类,变量的赋值是引用的传递。这是和结构体不同之处
2、生成一个对象的副本,这个对象的其他属性值与原对象相同,只有一个或者少数几个属性改变。麻烦的做法:
User u2 = new User(u1.UserName, "test@example", u1.Age);
3、用with关键字简化:
User u2 = u1 with { Email= “test@example” };
创建的也是拷贝