目录
只读成员
C#8.0中,可将readonly修饰符应用于结构的成员,它指示该成员不会修改状态。这比将readonly修饰符直接用于struct声明更加精准。
class MyTest
{
public readonly void Show()
{
Console.WriteLine("hi");
}
}
默认接口方法
C#8.0可以将成员添加到接口,并为这些成员提供实现。 借助此语言功能,API 作者可以将方法添加到以后版本的接口中,而不会破坏与该接口当前实现的源或二进制文件兼容性。 现有的实现继承默认实现 。 此功能使 C# 与面向 Android 或 Swift 的 API 进行互操作,此类 API 支持类似功能。 默认接口方法还支持类似于“特征”语言功能的方案。
interface TestService | Hi
{
public void Hi()
{
Console.WriteLine("hi")
}
}
升级的switch表达式
publicenum Rainbow
{
Red,
Orange,
Yellow,
Green,
Blue,
Indigo,
Violet
}
通过枚举获取颜色RGB值
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),
_ => thrownew ArgumentException(message: "invalid enum value", paramName: nameof(colorBand)),
};
变量位于 switch 关键字之前
2.将 case
和 :
元素替换为 =>
(此处借鉴了lambda表达式的语法格式)
3.将 default
事例替换为 _
弃元
4.正文是表达式,不是语句
属性模式
借助属性模式 ,可以匹配所检查的对象的属性。
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
};
public struct Address
{
public string State { get; set; }
}
元组模式
一些算法依赖于多个输入。 使用元组模式,可根据表示为元组的多个值进行切换 。
public static string RockPaperScissors(string first, string second)
=> (first, second) switch
{
("rock", "paper") => "rock is covered by paper. Paper wins.",
("rock", "scissors") => "rock breaks scissors. Rock wins.",
("paper", "rock") => "paper covers rock. Paper wins.",
("paper", "scissors") => "paper is cut by scissors. Scissors wins.",
("scissors", "rock") => "scissors is broken by rock. Rock wins.",
("scissors", "paper") => "scissors cuts paper. Scissors wins.",
(_, _) => "tie"
};
位置模式
某些类型包含 Deconstruct 方法,该方法将其属性解构为离散变量。 如果可以访问 Deconstruct 方法,就可以使用位置模式 检查对象的属性并将这些属性用于模式。
public class XPoint
{
public int X { get; set; }
public int Y { get; set; }
public void Deconstruct(out int x, out int y)
{
x = X;
y = Y;
}
}
public int GetNumber(XPoint point) => point switch
{
(0, 0) => 0,
var (x, y) when x > 0 && y > 0 => 1,
var (x, y) when x < 0 && y > 0 => 2,
var (x, y) when x < 0 && y < 0 => 3,
var (x, y) when x > 0 && y < 0 => 4,
var (_, _) => -1,
_ => -2
};
Using声明
using 声明 是前面带 using 关键字的变量声明。 它指示编译器声明的变量应在封闭范围的末尾(也就是执行到using的闭合花括号处)进行处理,对using引用的对象,要继承于IDisposable接口,因为在using块执行完毕后会自动调用该实例对象的Dispose()方法,将其释放,这也是为什么使用using的原因,它将代码简化了。
C#8.0中,使用using可以不再将其用括号括起来,而是像一个关键字一样,在加在对象声明语句的开头.
public void UsingStatement()
{
using var file = new System.IO.StreamWriter("WriteLines2.txt");
}
静态本地函数
现在可以向本地函数添加 static
修饰符,以确保本地函数不会从封闭范围捕获(引用)任何变量。
static void Main(string[] args)
{
int x = 100;
int y = 200;
static int sum(int x, int y) => x + y;
}
null合并赋值
当左操作数计算为 null
时,将??=
右操作数的值分配给左操作数
static void Main(string[] args)
{
string name = null;
name ??= "123";
}
异步流
从 C# 8.0 开始,可以创建并以异步方式使用流。 返回异步流的方法有三个属性:
- 它是用 async 修饰符声明的。
- 它将返回 IAsyncEnumerable<T>。
- 该方法包含用于在异步流中返回连续元素的 yield return 语句。
使用异步流需要在枚举流元素时在 foreach 关键字前面添加 await 关键字。 添加 await 关键字需要枚举异步流的方法,以使用 async 修饰符进行声明并返回 async 方法允许的类型。 通常这意味着返回 Task 或 Task<TResult>。 也可以为 ValueTask 或 ValueTask<TResult>。 方法既可以使用异步流,也可以生成异步流,这意味着它将返回 IAsyncEnumerable<T>。
public static class AsyncStream
{
public static async System.Collections.Generic.IAsyncEnumerable<int> GenerateSequence()
{
for (int i = 0; i < 20; i++)
{
await Task.Delay(100);
yield return i;
}
}
public static async void GetNumbers()
{
var c = CSharp8.AsyncStream.GenerateSequence();
await foreach (var number in c)
{
Console.WriteLine(number);
}
}
}
索引和范围
索引和范围为访问序列中的单个元素或者一段范围提供了简洁的语法。此语言支持依赖于两个新类型和两个新运算符:System.Index 表示一个序列索引来自末尾运算符 ^ 的索引,指定一个索引与序列末尾相关System.Range 表示序列的子范围,范围运算符 ..,用于指定范围的开始和末尾,就像操作数一样
private class IndexRange
{
string[] words = new string[]
{
// index from start index from end
"The", // 0 ^9
"quick", // 1 ^8
"brown", // 2 ^7
"fox", // 3 ^6
"jumped", // 4 ^5
"over", // 5 ^4
"the", // 6 ^3
"lazy", // 7 ^2
"dog" // 8 ^1
}; // 9 (or words.Length) ^0
void Test()
{
//>=index_1 && < index_4 包含 0 1 2 3 不包含4
var quickBrownFox = words[1..4];
var lazyDog = words[^2..^0];
}
}