Readonly 成员
可将 readonly 修饰符应用于结构的成员。 它指示该成员不会修改状态。
switch 表达式
更新增加新语法,可以直接使用枚举类型或类的判断条件
了解即可,旧语法同样可以。只不过增加了对元组的支持。
一个枚举对象如下
public enum Rainbow
{
Red,
Orange,
Yellow,
Green,
Blue,
Indigo,
Violet
}
常规的switch语句如下
public static RGBColor FromRainbowClassic(Rainbow colorBand)
{
switch (colorBand)
{
case Rainbow.Red:
return new RGBColor(0xFF, 0x00, 0x00);
case Rainbow.Orange:
return new RGBColor(0xFF, 0x7F, 0x00);
case Rainbow.Yellow:
return new RGBColor(0xFF, 0xFF, 0x00);
case Rainbow.Green:
return new RGBColor(0x00, 0xFF, 0x00);
case Rainbow.Blue:
return new RGBColor(0x00, 0x00, 0xFF);
case Rainbow.Indigo:
return new RGBColor(0x4B, 0x00, 0x82);
case Rainbow.Violet:
return new RGBColor(0x94, 0x00, 0xD3);
default:
throw new ArgumentException(message: "invalid enum value", paramName: nameof(colorBand));
};
}
而新增语法可以将switch语法优化
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)),
};
注意几点
- 变量位于 switch 关键字之前。 不同的顺序使得在视觉上可以很轻松地区分 switch 表达式和 switch 语句。
- 将 case 和 : 元素替换为 =>。 它更简洁,更直观。
- 将 default 事例替换为 _ 弃元。
- 正文是表达式,不是语句。
对类的对象,可以使用如下用法
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 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"
};
using 声明
using
可以不使用{}全部括起来,可以在函数作用范围结束后自动释放回收。
static int WriteLinesToFile(IEnumerable<string> lines)
{
using var file = new System.IO.StreamWriter("WriteLines2.txt");
// Notice how we declare skippedLines after the using statement.
int skippedLines = 0;
foreach (string line in lines)
{
if (!line.Contains("Second"))
{
file.WriteLine(line);
}
else
{
skippedLines++;
}
}
// Notice how skippedLines is in scope here.
return skippedLines;
// file is disposed here
}//执行后 此处释放file
相当于
static int WriteLinesToFile(IEnumerable<string> lines)
{
// We must declare the variable outside of the using block
// so that it is in scope to be returned.
int skippedLines = 0;
using (var file = new System.IO.StreamWriter("WriteLines2.txt"))
{
foreach (string line in lines)
{
if (!line.Contains("Second"))
{
file.WriteLine(line);
}
else
{
skippedLines++;
}
}
} // file is disposed here
return skippedLines;
}
异步流
C# 8.0 开始,可以创建并以异步方式使用流。 返回异步流的方法有三个属性:
- 它是用 async 修饰符声明的。
- 它将返回 IAsyncEnumerable。
- 该方法包含用于在异步流中返回连续元素的 yield return 语句。
官方文档举例如下,个人觉得如果使用异步还需要获取值,那么还不如直接await等待函数执行完,获取返回值。
public static async System.Collections.Generic.IAsyncEnumerable<int> GenerateSequence()
{
for (int i = 0; i < 20; i++)
{
await Task.Delay(100);
yield return i;
}
}
await foreach (var number in GenerateSequence())
{
Console.WriteLine(number);
}
索引和范围
这个新特性不错,python中的数组遍历实在是方便。现在c#终于增加了特性。
官方说明如下
此语言支持依赖于两个新类型和两个新运算符:
- System.Index 表示一个序列索引。 来自末尾运算符 ^ 的索引,指定一个索引与序列末尾相关。
- System.Range 表示序列的子范围。 范围运算符 …,用于指定范围的开始和末尾,就像操作数一样。
首先一个数组
var 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
获取最后一个元素旧语法为
words[words.length-1]
新版本
words[^1]
获取一定范围的数组,注意左闭右开,包括左边的,不包含右侧的,下方的意思是获取1-3的元素 “quick”、“brown”和“fox”
var quickBrownFox = words[1..4];
以下代码创建了一个包含单词“quick”、“brown”和“fox”的子范围。 它包括 words[1] 到 words[3]。 元素 words[4] 不在该范围内。
var lazyDog = words[^2..^0];
以下代码使用“lazy”和“dog”创建一个子范围。 它包括 words[^2] 和 words[^1]。 末尾索引 words[^0] 不包括在内:
var lazyDog = words[^2..^0];
下面的示例为开始和/或结束创建了开放范围:
var allWords = words[..]; // contains "The" through "dog".
var firstPhrase = words[..4]; // contains "The" through "fox"
var lastPhrase = words[6..]; // contains "the", "lazy" and "dog"
此外可以将范围声明为变量:
Range phrase = 1..4;
var text = words[phrase];
Null 合并赋值
**合并赋值运算符 **??=
仅当左操作数计算为 null 时,才能使用运算符 ??= 将其右操作数的值分配给左操作数。
//声明两个为空的对象
List<int> numbers = null;
int? i = null;
//numbers为null 右侧赋值给左侧
numbers ??= new List<int>();
//i为Null 赋值17
numbers.Add(i ??= 17);
//i不为null 不操作 保留原值
numbers.Add(i ??= 20);
Console.WriteLine(string.Join(" ", numbers)); // output: 17 17
Console.WriteLine(i); // output: 17