个人推荐去微软官方文档查看,以下是个人总结,不全
微软官方文档:https://learn.microsoft.com/zh-cn/dotnet/csharp/whats-new/csharp-10
8.0特性 8.0特性一览
1、可空类型:
运行int?这种写法,意为int肯能为null
2、async/await允许直接获取结果
var a = await ……;
配合IAsyncEnumerable,可异步循环返回结果
async IAsyncEnumerable<int> GetBigResultsAsync() {
await foreach (var result in GetResultsAsync()) {
if (result > 20) yield return result;
}
}
3、Ranges and indices 范围和索引
Index i1 = 3;
Index i2 = ^4;
int[] a = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
Console.WriteLine($"{a[i1]}, {a[i2]}"); // "3, 6"
var slice = a[i1..i2]; // { 3, 4, 5 }
4、接口成员的默认实现
给已有接口添加方法时,可默认实现方法,防止编译失败
interface AA {
void Test() => Console.WriteLine("11");
}
5、递归的模式匹配
public class Program {
public static void Main(string[] args) {
Student[] student = new Student[] {
new Student{ Graduated = true, Name="0" },
new Student{ Graduated = false, Name="1" },
new Student{ Name="2" },
new Student{ Graduated = true },
new Student{ Graduated = true, Name=null },
new Student{ Graduated = true, Name="5" },
};
Console.WriteLine(string.Join(",", GetEnrollees(student)));
}
static IEnumerable<string> GetEnrollees(Student[] People) {
foreach (var p in People) {
if (p is Student { Graduated: true, Name: string name })
yield return name;
}
}
}
class Student {
public bool Graduated;
public string Name;
}
关键代码解释:p is Student { Graduated: true, Name: string name }
Graduated: true:判断p里面的Graduated参数必须为true
Name: string name,对p里面的Name进行取值(如果可为空)
等效于
if (p is Student s && s.Graduated == true && s.Name != null) {
string neme = p.Name;
}
为何会有个s.Name != null,因为string是可空类型,不是可空将不会进行空值判断,例如int不是可空类型,但是int?是
6、switch表达式
匹配模式的增强
int num = 2;
string text = num switch {
1 => "1",
2 => "2",
_ => "3"//default
};
7、已知目标类型的新表达式
public class Program {
public static void Main(string[] args) {
Student[] arr = { new(0, "0"), new(true) };
}
}
class Student {
public Student(int a, string b) {
}
public Student(bool b) {
}
}
9.0特性9.0特性一览
1、init关键字
init代替set,意为:只允许初始化时赋值,后续不可赋值
public class Program {
public static void Main(string[] args) {
Student s = new Student { name = "a" };
s.name = "b";//异常,不可赋值
}
}
class Student {
public string name { get; init; }
}
2、record关键字
个人简单理解:赋予结构体相关特性,进行视为值类型
C#中的记录(record)
3、with关键字
非破坏性拷贝,配合record或struct,拷贝数据
public class Program {
public static void Main(string[] args) {
Student s = new Student { name = "a", age = 18 };
Student s2 = s with { age = 10 };
AA a = new AA { name = "" };
AA a2 = a with { name = "a" };
}
}
record class Student {
public string name;
public int age;
}
struct AA {
public string name;
}
4、顶层语句
整个cs文件就这么点内容也能运行
string name = "1";
Console.WriteLine(name);
5、匹配模式增强
模式匹配是在 C# 7.0 引入的,是对 switch 语句的增强,可以支持实现复杂的条件匹配
public class Program {
public static void Main(string[] args) {
A a = new B();
int num = a switch {
B { numb: 10 } => 0,//如果a是B类型,并且参数numb是10,则返回0
B => -1,//default语句,如果是B类型,但都匹配不上,则返回-1
C c => c.numc switch {//如果是C类型,对C类型的numc进行匹配模式
> 10 => 1,//如果大于10,返回1
> 0 and < 5 => 2,//如果大于0小于5,返回2,还有or、not 关键字,优先级is > not > and > or
_ => -2//都不匹配返回-2
},
not null => 3,//不是空返回3
_ => 4
};
}
}
class A {
public int numa;
}
class B : A {
public int numb;
}
class C : A {
public int numc;
}
6、返回值类型协变
重写时可对返回值类型具体化
class A {
}
class B : A {
}
abstract class C {
public abstract A Test();
}
class D : C {
public override B Test() {//用B,进行更具体的返回
throw new NotImplementedException();
}
}
7、本地大小的整型nint/nuint
这两种类型的大小是32还是64的取决于所用平台。在被编译之后,这两个关键字会被转换为System.IntPtr 和System.UIntPtr。
8、静态匿名方法
public class Program {
public static void Main(string[] args) {
int num = 10;
Action<int> nc = static (int a) => Console.WriteLine(a + num);//异常,加static后无法捕获num
Action<int> nc2 = static delegate (int a) { Console.WriteLine(a + num); };//异常,加static后无法捕获num
}
}
9、模块初始化器
类似于静态构造方法的另一种实现
C# 9.0新特性详解系列之三:模块初始化器
10、本地函数支持Attribute
静态方法和extern关键字修饰的也支持特性了[]
11、partial可用于方法上
partial class MyClass {
// 正确,因为没有定义或者实现要求
partial void Method1();
// 正确,因为M2已经有了一个定义和实现了
private partial void Method2();
// 错误,含有显式访问修饰符的分部方法声明必须有一个实现
private partial void Method3();
}
partial class MyClass {
private partial void Method2() { }
}
12、Lambda弃元参数
就是_字符
public static void Main(string[] args) {
Action<int> a = (int _) => Console.WriteLine("OK");
}
13、目标类型推导
public class Program {
public static void Main(string[] args) {
string[] s2 = new[] { "a", "b" };
Test t = new(2);
//同时支持??, ?:表达式
}
}
class Test {
public Test(int a) {
}
}
10.0特性10.0特性一览
1、record支持给struct修饰
2、struct支持无参构造
3、with支持支持匿名类
public class Program {
public static void Main(string[] args) {
var a = new { name = "张三", age = 10 };
var b = a with { age = 18 };//name已经是张三
}
}
4、全局using
using前面加global,作用到全局,可单独创个文件写
5、文件范围的namespace
写法:namespace xxxxxx;
6、const string支持$""写法
const string t = "99";
const string s = $"12{t}4";
7、lambda表达式升级
public static void Main(string[] args) {
var a = [DebuggerStepThrough] () => 1;//lambda支持特性
var b = ref int (ref int num, out int num2) => {
num2 = 10;
num += 10;
return ref num;
};//支持ref、in、out修饰符
//隐式转换为delegata
Func<int> f = a;
void Test() { Console.WriteLine("OK"); };
var f2 = Test;
f2();
//自动创建自然委托类型
var t1 = () => 1;//Func<int>
var t2 = string (int a1, string a2) => $"{a1}{a2}";//Func<int, string, string>
}
8、CallerArgumentExpression特性
可以方便调试,Release版本也行
public class Program {
public static void Main(string[] args) {
Test(9 * 8 - 10);//9 * 8 - 10=62
int a = 10;
Test(a + 5);//a + 5=15
}
public static void Test(int num, [CallerArgumentExpression("num")]string text = null) {
Console.WriteLine($"{text}={num}");
}
}
9、System.ValueTuple支持混合定义和使用
int a = 0;
(var b, a, var c) = (1, 2, 3);//a等于2的同时创建了2个新变量
10、Attribute支持泛型
11、运行在方法上指定[AsyncMethodBuilder]
12、#line指示器支持行列和范围
13、嵌套模式匹配升级
var a = xxxx;
if (a is { X.Y.Z:4 }) {//a的X中的Y中的Z是4就匹配
}