减少援用类型可为null:

//如果参数t是null,则会收回正告public static void Test<T?>(T t){            }

模式匹配

1、swith 多条件匹配

## 1 元组模式 int a = 1;int b = 10; string c = (a, b) switch { (1, 10) =>  "123",  _ =>  "default",};### 应用弃元模式_ = (a, b) switch {    (1, 10) =>  "123",     _ =>  "default",};## 2 地位模式    public class PointA    {        public int X { get; }                public int Y { get; }        public int Z { get; }        public PointA(int x, int y) => (X, Y) = (x, y);        public PointA(int x, int y,int z) => (X, Y,Z) = (x, y,z);        public void Deconstruct(out int x, out int y) => (x, y) = (X, Y);        public void Deconstruct(out int x, out int y,out int z) => (x, y,z) = (X, Y,Z);    }static string GetLocation(PointA point) => point switch        {            (0, 0) => "1",            (0, 0, 0) => "1",            var (x, y) when x > 0 && y > 0 =>"2",            var (_, _) => "3",// 当 x 或 y 不为null时            _ => "4"   };

Using 申明

## 先相熟下应用 此处 C#7就能用了using static System.Math;using Tasks = System.Threading.Tasks;using (FileStream fileStream = new FileStream("", FileMode.Open))  {  }##  C#8using FileStream fileStream2 = new FileStream("", FileMode.Open);

接口个性减少

--- 能够申明一个属性
--- 办法能够实现(不再是只定义)

  public interface MyInterface    {        public int Age { get; set; }        void Method1(int age)        {            Console.WriteLine(age);        }    }

Readonly 成员

public readonly struct Coords  {      public Coords(double x, double y)        {            X = x;            Y = y;        }      public double X { get; set; }      public double Y { get; set; }      public override string ToString() => $"({X}, {Y})";  }

---- 构造体 部分只读

public struct Coords{      public double X { get; set; }      public double Y { get; set; }      private int counter;      public  int Counter        {            readonly get => counter;            set => counter = value;        }     /*public Coords(double x, double y, int _counter)        {            X = x;            Y = y;            counter = _counter;        }*/      public override string ToString() => $"({X}, {Y})";      public readonly double Sum()        {            /*X = 200;            Y = 200;*/            return X + Y;        }  }

动态本地函数

总结

反对禁止从关闭范畴捕捉状态的本地函数。

具体设计

申明的本地函数 static 无奈从关闭范畴中捕捉状态。 因而, this 部分函数中不提供关闭范畴内的局部变量、参数和 static 。
static部分函数不能通过隐式或显式或援用来援用实例成员 this base 。
static部分函数能够援用 static 关闭范畴内的成员。

static int z = 0; int InnerMethod(){    int y = 5;    int x = 7;           return LocalStaticFunction(x, y);    //动态本地函数    static int LocalStaticFunction(int left, int right) {                return z + left + right;    }}

异步流

C#8.0之前 反对迭代器办法和异步办法,但不反对同时作为迭代器和异步的办法。 咱们应该通过容许 await 应用新的迭代器模式来纠正这种状况 async ,它将返回 IAsyncEnumerable<T> 或 IAsyncEnumerator<T> 而不是 IEnumerable<T> 或 IEnumerator<T> , IAsyncEnumerable<T> 在新的中应用 await foreach 。 IAsyncDisposable接口还用于启用异步清理。

新增接口: IAsyncDisposable 、IAsyncEnumerable/IAsyncEnumerator

通常状况下,任何时候清理资源所需的工夫可能会很有用,例如敞开文件 (须要刷新) ,勾销注册回调并提供一种办法来理解登记实现的工夫等。

namespace System{    public interface IAsyncDisposable    {        ValueTask DisposeAsync();    }}

与一样 Dispose , DisposeAsync 屡次调用都是可承受的,并且第一次调用之后的调用应被视为 nops(意味着后续调用都应该是 nop),返回同步实现的工作 (DisposeAsync 不须要线程平安的,并且无需反对) 的并发调用。
名称解释:nop不执行任何操作

namespace System.Collections.Generic{    public interface IAsyncEnumerable<out T>    {        IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default);    }    public interface IAsyncEnumerator<out T> : IAsyncDisposable    {        ValueTask<bool> MoveNextAsync();        T Current { get; }    }}
IAsyncEnumerator<T> enumerator = enumerable.GetAsyncEnumerator();try{    while (await enumerator.MoveNextAsync())    {        Use(enumerator.Current);    }}finally { await enumerator.DisposeAsync(); }
static async void Main(string[] args) {    IAsyncEnumerable<string> asyncEnumerable = AsyncEnumerableTest();    IAsyncEnumerator<string> asyncEnumerator = asyncEnumerable.GetAsyncEnumerator();    try{       while (await asyncEnumerator.MoveNextAsync()) {           Console.WriteLine(asyncEnumerator.Current);           }     }    finally { await asyncEnumerator.DisposeAsync(); }}## 异步迭代器,但await不能在这些迭代器的主体中应用private static async IAsyncEnumerable<string> AsyncEnumerableTest(){    await Task.Delay(100);    yield return "001";    yield return "002";    yield return "003";    yield return "004";    yield return "005";}
  • _Task<bool> MoveNextAsync(); T current { get; }_:应用 Task<bool> 将反对应用缓存的工作对象来示意同步、胜利的 MoveNextAsync 调用,但异步实现仍须要调配。 通过返回 ValueTask<bool> ,咱们容许枚举器对象本身实现 IValueTaskSource<bool> 并用作从返回的的后备 ValueTask<bool> MoveNextAsync ,这反过来容许大大降低开销。
  • _ValueTask<(bool, T)> MoveNextAsync();_:更难应用,但这意味着它 T 不再是协变的。

foreach 引入异步

若要强制 foreach 改为仅思考异步 api,请按 await 如下所示插入:

await foreach (var i in enumerable)
var enumerable = ...; await foreach (T item in enumerable) {    ... } ### 转换为的等效项:var enumerable = ...;var enumerator = enumerable.GetAsyncEnumerator();try{    while (await enumerator.MoveNextAsync())    {       T item = enumerator.Current;       ...    }}finally{    await enumerator.DisposeAsync(); // omitted, along with the try/finally, if the enumerator doesn't expose DisposeAsync}

ConfigureAwait
此基于模式的编译容许 ConfigureAwait 通过扩大办法在所有期待中应用

await foreach (T item in enumerable.ConfigureAwait(false)){   ...}###这将基于咱们还将增加到 .NET 的类型,可能会 System.Threading.Tasks.Extensions.dll:

LINQ减少异步办法

List<string> list = new List<string>();            list.Add("001");            list.Add("002");            list.Add("003");            list.Add("004");            list.Select(AsyncMethod);async ValueTask<string> AsyncMethod(string item){         await Task.Yield();        return item + "-";}
List<string> list = new List<string>();            list.Add("001");            list.Add("002");            list.Add("003");            list.Add("004");            list.Select(async (item) =>            {                await Task.Yield();                return item + "-";            });
 public partial class Form1 : Form    {        CancellationTokenSource cancellationToken;        public Form1()        {            InitializeComponent();        }        private async void button1_Click(object sender, EventArgs e)        {            cancellationToken = new CancellationTokenSource();            CancellationToken token = cancellationToken.Token;            IAsyncEnumerable<int> enumerable = ReadIntAsync(token);            await Task.Delay(3000);            //设置要在循环拜访时传递到 GetAsyncEnumerator(CancellationToken) 的 CancellationToken。            //enumerable.WithCancellation(token);            IAsyncEnumerator<int> enumerator = enumerable.GetAsyncEnumerator();            try            {                while (await enumerator.MoveNextAsync())                {                    Debug.WriteLine(enumerator.Current);                }            }            catch (TaskCanceledException ex1)            {                Console.WriteLine(ex1.Message);            }            catch (OperationCanceledException ex2)            {                Console.WriteLine(ex2.Message);            }            finally            {                await enumerator.DisposeAsync();            }        }        private void button2_Click(object sender, EventArgs e)        {            cancellationToken = cancellationToken??new CancellationTokenSource();            cancellationToken.Cancel();        }                        private async IAsyncEnumerable<int> ReadIntAsync([EnumeratorCancellation] CancellationToken _token)        {            try            {                for (int i = 0; i < 20; i++)                {                    //勾销工作及其子级                    if (_token.IsCancellationRequested)                    {                        _token.ThrowIfCancellationRequested();                    }                    await Task.Delay(200, _token);                    yield return i;                }            }            finally            {                Console.WriteLine("finally");            }        }    }

索引和范畴

此性能与提供两个新的运算符,它们容许结构 System.Index 和 System.Range 对象,并应用它们在运行时索引/切片汇合。

namespace System{    public readonly struct Index    {        public Index(int value, bool fromEnd);    }}

若要 System.Index 在数组元素拜访中应用类型作为参数,须要以下成员:

int System.Index.GetOffset(int length);
int[] arr = new int[6] { 132, 67, 47, 58, 83,100};
Index index = new Index(8, true);
--- 偏移量
int offset = index.GetOffset(arr.Length);

的 .. 语法 System.Range 须要该 System.Range 类型,以及以下一个或多个成员:

namespace System{    public readonly struct Range    {        public Range(System.Index start, System.Index end);        public static Range StartAt(System.Index start);        public static Range EndAt(System.Index end);        public static Range All { get; }    }}

最初,对于 System.Range 要在数组元素拜访表达式中应用的类型值,必须存在以下成员:

//System.Runtime.CompilerServices=> 意味着编译器一开始就能够编译namespace System.Runtime.CompilerServices{    public static class RuntimeHelpers    {        public static T[] GetSubArray<T>(T[] array, System.Range range);    }}
语言会引入新的范畴运算符 x..y 。 它是一个承受两个表达式的二元中断运算符
System.Range operator ..(Index start = 0, Index end = ^0);
.. 将运算符称为 范畴运算符
 public Index(int value, bool fromEnd);
运算符 ^ 等价于 Index(int value, bool fromEnd)

示例:

int[] arr = new int[6] { 132, 67, 47, 58, 83,100};//获取前三个元素 以某某作为截止int[] vs1 = RuntimeHelpers.GetSubArray(arr, Range.EndAt(3));//获取后三个元素 以某某作为开始int[] vs2 = RuntimeHelpers.GetSubArray(arr, Range.StartAt(3));Console.WriteLine(vs2);
 Range range1 = Range.StartAt(2);//从第三个元素开始 startIndex<=x<lenth Range range2 = new Range(2, 4);//从第三个元素开始 到第四个元素 startIndex<=x<endIndex var array = new int[] { 1, 2, 3, 4, 5 }; var slice1 = array[range1];   var slice2 = array[range2];  

fromEnd为true 从尾部计算下标 :offset = arr.length-index;

new Index(index, fromEnd: true).GetOffset(array.Length)

var array = new int[] { 1, 2, 3, 4, 5 };var lastItem = array[^1];    // array[new Index(1, fromEnd: true)]var slice1 = array[2..^3];    // array[new Range(2, new Index(3, fromEnd: true))]var slice2 = array[..^3];     // array[Range.EndAt(new Index(3, fromEnd: true))]var slice3 = array[2..];      // array[Range.StartAt(2)]var slice4 = array[..];       // array[Range.All]

此外, System.Index 应从进行隐式转换 System.Int32 ,以防止对多维签名重载混合整数和索引的需要。

此新优先级组低于_一元运算符_ ,大于_乘法算术运算符_

内插逐字字符串的加强性能

内插字符串的构造

若要将字符串标识为内插字符串,可在该字符串后面加上 $ 符号。 字符串字面量结尾的 $ 和 " 之间不能有任何空格。 若要连贯多个内插字符串,请将 $ 特殊字符增加到每个字符串字面量。
具备内插表达式的项的构造如下所示:

 {<interpolationExpression>[,<alignment>][:<formatString>]}
元素形容
interpolationExpression生成须要设置格局的后果的表达式。 null 的字符串示意模式为 String.Empty。
alignment常数表达式,如果值为正,则字符串示意模式为右对齐;如果值为负,则为左对齐。 数值为意味着字符串占位长度,如果小于表达式理论值 则以理论值长度计算。
formatString受表达式后果类型反对的格局字符串。 无关更多信息,请参阅格局字符串组件。

如工夫格局:MM/dd/yy H:mm:ss zzz
GUID格局: N 或者 D (见下方示例) |

Console.WriteLine($"|{"Left000"}|{"000Right"}|");Console.WriteLine($"|{"Left",-7}|{"Right",7}|");---输入后果:--|Left000|000Right||Left   |  Right|-----Guid guid = Guid.NewGuid();Console.WriteLine($"{guid:N}");

小破站: https://www.bilibili.com/video/BV1E24y147Vc
抖茵: https://www.douyin.com/user/self?modal_id=7217801169001844007&showTab=post