盘点C# 8.0中好用的特性

2023-11-10

增加引用类型可为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#8
using 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 或 IAsyncEnumerator 而不是 IEnumerable 或 IEnumerator , IAsyncEnumerable 在新的中使用 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 MoveNextAsync(); T current { get; }:使用 Task 将支持使用缓存的任务对象来表示同步、成功的 MoveNextAsync 调用,但异步完成仍需要分配。 通过返回 ValueTask ,我们允许枚举器对象自身实现 IValueTaskSource 并用作从返回的的后备 ValueTask 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

var code = “a8dc524f-024c-45a3-a930-6b91fb4908bf”

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

盘点C# 8.0中好用的特性 的相关文章

随机推荐

  • Ubuntu 14.04 Tab补全忽略大小写

    0 前言 当目录名以大写字母开头时 通过cd命令进入该目录就不太方便 需要切换到大写输入 如果Tab补全可以忽略大小写的话 这个问题就引刃而解 1 设置方法 1 在 目录中创建 inputrc 2 打开 inputrc 添加如下设置 set
  • 面向产品分析的内容

    声明 本文是学习GB T 42859 2023 航天产品质量问题三个面向分析方法实施要求 而整理的学习笔记 分享出来希望更多人受益 如果存在侵权请及时联系我们 1 范围 本文件规定了航天产品质量问题三个面向分析方法实施的一般要求 程序和分析
  • Pandas库基础知识(一)

    文章目录 1 数据结构 1 Series 数据结构 1 Series对象的创建 2 Series对象的属性 3 Series对象的基本操作 2 DataFrame 数据结构 1 DataFrame对象的创建 2 DataFrame对象的属性
  • scrapy-redis分布式爬虫框架详解

    scrapy redis分布式爬虫框架详解 随着互联网技术的发展与应用的普及 网络作为信息的载体 已经成为社会大众参与社会生活的一种重要信息渠道 由于互联网是开放的 每个人都可以在网络上发表信息 内容涉及各个方面 小到心情日志 大到国家大事
  • sqllab 1-6 练习

    前言 什么是sql注入 攻击者通过构造不同的sql语句来实现对数据库的操作 两个关键 参数用户可控 参数带入数据库查询 基本流程 判断注入点 判断字段数 判断回显点 查询相关内容 判断库名 gt 判断表明 gt 判断列名 gt 判断数据 搭
  • xxl-job详细使用指南

    新建任务说明 本篇文章承接上文 xxl job快速入门指南 上一次和大家简单介绍了下 xxl job 的由来以及使用方法 本篇文章将会详细介绍一些高级使用方法及特性 上文中我们在新建一个任务的时候发现有很多的选项 现在我们来详细聊一聊他们的
  • Jquery加载本地文件出现跨域错误的解决方案

    禁止跨域是浏览器的安全限制机制 会报告上述错误 但是可以通过设置来绕过这个限制 如果经常调试前端代码 可以在本机装个web容器 常见的方式 右击chrome快捷方式 选择 属性 在 快捷方式 下的 目标 中添加 allow file acc
  • HT for Web (Hightopo) 使用心得(6)- 3D场景环境配置(天空球,雾化,辉光,景深)

    在前一篇文章 Hightopo 使用心得 5 动画的实现 中 我们将一个直升机模型放到了3D场景中 同时 还利用动画实现了让该直升机围绕山体巡逻 在这篇文章中 我们将对上一篇的场景进行一些环境上的丰富与美化 让场景更真实一些 具体涉及到的知
  • 微信小程序基础入门的知识点

    微信小程序基础入门的知识点 1 窗口配置 就是在我们app json文件就是对我们微信小程序进行全局配置 它决定我们页面文件的路径 设置多个tab 1 1 pages设置页面的路径 数组的第一个就是我们小程序初始页面 文件名不需要我们写文件
  • C语言入门之自定义结构体数据struct Student { int num; char name[20]; char sex; int age; 类型

    用户自己建立由不同类型数据组成的组合型的数据结构 它称为结构体 例如 一个学生的学号 姓名 性别 年龄 成绩 家庭地址等项 是属于同一个学生的 因此组成一个组合数据 如student 1的变量 反映它们之间的内在联系 struct Stud
  • 字节跳动,华为,阿里巴巴,小米,腾讯 2021大厂面试经历系列之初、中、高级测试工程师面试题汇总(附答案)

    前言 最近看到很多人都在找工作 而且很多人都感觉今年找工作比去年难很多 竞争力也增加不少 因此激发我整理这份资料 希望能帮到正在找或者准备找工作的童鞋们 首先我们能否获得一个面试机会 那肯定是从简历开始 简历需要做好功夫 一份好的简历才足够
  • Springboot集成Jasypt实现配置文件加密

    不容错过的成长之旅 Jasypt介绍 Jasypt是一个java库 它允许开发员以最少的努力为他 她的项目添加基本的加密功能 并且不需要对加密工作原理有深入的了解 用于单向和双向加密的高安全性 基于标准的加密技术 加密密码 文本 数字 二进
  • 解决Windows10中文用户名带来软件无法打开的影响

    众所周知 许多国外的开发软件都不支持中文的文件路径名 即使软件的路径无中文字符 可你系统用户的名称是中文 同样软件无法运行 因为大部分软件的在电脑用户上的缓冲文件都是在 C user 你的用户名称 AppData local temp 解决
  • Power BI和Tableau对比分析,到底要学哪个?

    Power BI和Tableau对比分析 到底要学哪个 一 两个工具优缺点 Power BI Tableau 二 职业需求 前程无忧 智联招聘 三 总结 学习tableau还是power bi想必是很多初学者的疑惑 可以从以下两个角度去考虑
  • 一台服务器想用150个ip,可以吗?

    不可以 一台服务器一次只支持一个ip 可以更换 但每次绑定一个 如果需要多个ip 只能多开服务器 挂店铺的 包括淘宝店铺 拼多多店铺 亚马逊店铺都想店铺不被关联 想买台服务器 可以的 一个店铺买一台服务器 有几个店铺就买几台服务器 ip的带
  • 数据结构:(代码篇:004)二叉搜索树 BST(二叉查找树)的基本操作

    1 基本概念 二叉搜索树 是二叉树是真子集 要求 根节点大于或等于左子树的节点值 小于右子树的节点值 他的中序遍历是有序的 基本操作有 查找 插入 删除 建树 查找和插入以及建树都很简单 和二叉树的差不多 删除略微复杂 2 存储结构 str
  • Apche Kafka + Spring的消息监听容器

    目录 一 消息的接收 1 1 消息监听器 二 消息监听容器 2 1 实现方法 2 1 1 KafkaMessageListenerContainer 2 1 1 1 基本概念 2 1 1 2 如何使用 KafkaMessageListene
  • SpringMVC异常处理

    1 概述 SpringMVC 框架处理异常的常用方式 使用 ExceptionHandler 注解处理异常 2 ExceptionHandler注解和用 ControllerAdvice注解 2 1 ExceptionHandler注解 使
  • VIVADO软件错误及解决办法汇总

    在VIVADO软件编写程序时会遇到很多类型的错误 写个博客记录下来防止再犯 短期可能只有几个问题 会长期保持更新 遇到问题就记录 2022 4 09 问题1 The debug port u ila 0 probe4 has 1 uncon
  • 盘点C# 8.0中好用的特性

    增加引用类型可为null 如果参数t是null 则会发出警告 public static void Test