- 索引与范围
- 索引 使用^操作符:^1指向最后一个元素,^2倒数第二个元素:
char[] vowels = new char[] {'a','e','i','o','u'}; char lastElement = vowels [^1]; // 'u' char secondToLast = vowels [^2]; // 'o'
- 范围 使用
..
操作符slice一个数组(左闭右开)char[] vowels = new char[] {'a','e','i','o','u'}; char[] firstTwo = vowels [..2]; // 'a', 'e' //从左边取两个 char[] lastThree = vowels [2..]; // 'i', 'o', 'u' 从2索引开始取 char[] middleOne = vowels [2..3] // 'i' 取2-3的值 char[] lastTwo = vowels [^2..]; // 'o', 'u'
- Index类型与Range类型 借助于Index类型和Range类型实现索引与范围
char[] vowels = new char[] {'a','e','i','o','u'}; Index last = ^1; Range firstTwoRange = 0..2; char[] firstTwo = vowels [firstTwoRange]; // 'a', 'e'
- 扩展-索引器
class Sentence {string[] words = "The quick brown fox".Split();public string this [Index index] => words [index];public string[] this [Range range] => words [range]; }
- 索引 使用^操作符:^1指向最后一个元素,^2倒数第二个元素:
- 空合并操作 ??=
old: string s=null; if(s==null)s="Hello,world";//s==null,s is Hello,world,or s is still snew: s??="hello,world";
- using声明 如果省略了using后面的{},及声明语句块,就变为了using declaration,当执行落到所包含的语句块之外时,该资源将被释放
if (File.Exists ("file.txt")) {using var reader = File.OpenText ("file.txt");Console.WriteLine (reader.ReadLine());... } 当执行走到if语句块之外时,reader才会被释放
- readonly成员
允许在结构体的函数中使用readonly修饰符,函数试图修改任何字段,会产生编译时错误 struct Point {public int X, Y;public readonly void ResetX() => X = 0; // Error! 不能修改值 }readonly函数调用一个非readonly成员,编译器会产生警告 public struct Point {public double X { get; set; }public double Y { get; set; }public double Distance => Math.Sqrt(X * X + Y * Y);public readonly override string ToString() =>$"({X}, {Y}) is {Distance} from the origin"; }//readonly修饰ToString方法中调用Distance没有readonly修饰所以会警告
- 静态本地函数
本地函数加上static,以确保本地函数不会从封闭范围捕获任何变量。 这样做会生成CS8421,“静态本地函数不能包含对 的引用”。这有助于减少耦合, 并使本地方法能够根据需要声明变量,而不会与包含的方法中的变量发生冲突 int M() {int y = 5;int x = 7;return Add(x, y);static int Add(int left, int right) => left + right; }Add()不访问封闭范围中的任何变量,当然如果Add函数访问了本地变量,那就有问题int M() {int y;LocalFunction();return y;static void LocalFunction() => y = 0; //warning }
- 默认接口成员
允许向接口成员添加默认实现,使其成为可选实现 interface ILogger {void Log (string text) => Console.WriteLine (text); }默认实现必须显式接口调用 class Logger : ILogger { } ... ((ILogger)new Logger()).Log ("message");接口也可以定义静态成员(包括字段),然后可以在默认实现中访问 interface ILogger {void Log (string text) => Console.WriteLine (Prefix + text);static string Prefix = ""; }在接口外部,因为接口成员是隐式公共的,所以还可以从接口外部访问静态成员的 ILogger.Prefix = "File log: ";
-
switch表达式
1、可以在一个表示式上下文中使用switch(switch关键字是在变量名之后,{}里面是case子句,要逗号) string cardName = cardNumber switch {13 => "King",12 => "Queen",11 => "Jack",_ => "Pip card" // equivalent to 'default' };2、还可以基于元组匹配 int cardNumber = 12; string suit = "spades";string cardName = (cardNumber, suit) switch {(13, "spades") => "King of spades",(13, "clubs") => "King of clubs",... };3、使用属性模式 System.Uri 类,具有属性Scheme, Host, Port, 和 IsLoopback.考虑如下场景:写一个防火墙, 我们可以使用switch表达式的属性模式来决定防火墙的规则(阻止或允许) bool ShouldAllow (Uri uri) => uri switch {{ Scheme: "http", Port: 80 } => true,{ Scheme: "https", Port: 443 } => true,{ Scheme: "ftp", Port: 21 } => true,{ IsLoopback: true } => true,_ => false };4、使用位置模式 包含可以访问的解构函数的Point类,可以使用位置模式 public class Point {public int X { get; }public int Y { get; }public Point(int x, int y) => (X, Y) = (x, y);public void Deconstruct(out int x, out int y) =>(x, y) = (X, Y); } 象限枚举 public enum Quadrant {Unknown,Origin,One,Two,Three,Four,OnBorder } 使用位置模式 来提取 x 和 y 的值。 然后,它使用 when 子句来确定该点的 Quadrant static Quadrant GetQuadrant(Point point) => point switch {(0, 0) => Quadrant.Origin,var (x, y) when x > 0 && y > 0 => Quadrant.One,var (x, y) when x < 0 && y > 0 => Quadrant.Two,var (x, y) when x < 0 && y < 0 => Quadrant.Three,var (x, y) when x > 0 && y < 0 => Quadrant.Four,var (_, _) => Quadrant.OnBorder,_ => Quadrant.Unknown };
-
可空引用类型
//可空s和s非空打印 void Foo (string? s) => Console.Write (s!.Length);
-
异步流
在C#8.0之前,可以使用yield返回一个迭代器(iterator),或者使用await编写异步函数。 但是如果想在一个异步函数返回一个迭代器怎么办? C#8.0引入了异步流-asynchronous streams,解决了这个问题 //async IAsyncEnumerable async IAsyncEnumerable<int> RangeAsync (int start, int count, int delay) {for (int i = start; i < start + count; i++){await Task.Delay (delay);yield return i;} }await foreach调用异步流 await foreach (var number in RangeAsync (0, 10, 100))Console.WriteLine (number);LINQ查询 IAsyncEnumerable<int> query = from i in RangeAsync (0, 10, 500)where i % 2 == 0 // Even numbers only.select i * 10; // Multiply by 10.await foreach (var number in query)Console.WriteLine (number);
-
$
和@
标记的顺序可以任意安排:$@"..."
和@$"..."
均为有效的内插逐字字符串,这个在C#6.0时,是有严格的顺序限制