C# 8.0 的新特性概览和讲解_micro_snow的博客-程序员宅基地

技术标签: c#  我的转载  

本文转自 https://blog.csdn.net/hez2010/article/details/84036742

前言

该文章的最新版本已迁移至个人博客【比特飞】,单击链接 https://www.byteflying.com/archives/1037 访问。

2018年11月12日微软在 MSDN 博客的 Building C# 8.01 一文发表了新的 C# 8.0 即将发布的特性,现在让我们来看一下。

新的改变

  1. 可空引用类型
  2. 异步流
  3. 范围和下标类型
  4. 接口成员的默认实现
  5. 模式匹配表达式和递归模式语句
  6. 目标类型推导

可空引用类型(Nullable reference types)

从此,引用类型将会区分是否可分,可以从根源上解决 NullReferenceException。但是由于这个特性会打破兼容性,因此没有当作 error 来对待,而是使用 warning 折衷,而且开发人员需要手动 opt-in 才可以使用该特性(可以在项目层级或者文件层级进行设定)。
例如:

string s = null; // 产生警告: 对不可空引用类型赋值 null
string? s = null; // Ok

void M(string? s)
{
    
    Console.WriteLine(s.Length); // 产生警告:可能为 null
    if (s != null)
    {
    
        Console.WriteLine(s.Length); // Ok
    }
}

至此,妈妈再也不用担心我的程序到处报 NullReferenceException 啦!

异步流(Async streams)

考虑到大部分 Api 以及函数实现都有了对应的 async版本,而 IEnumerable<T>IEnumerator<T>还不能方便的使用 async/await就显得很麻烦了。
但是,现在引入了异步流,这些问题得到了解决。
我们通过新的 IAsyncEnumerable<T>IAsyncEnumerator<T>来实现这一点。同时,由于之前 foreach是基于IEnumerable<T>IEnumerator<T>实现的,因此引入了新的语法await foreach来扩展 foreach的适用性。
例如:

async Task<int> GetBigResultAsync()
{
    
    var result = await GetResultAsync();
    if (result > 20) return result; 
    else return -1;
}

async IAsyncEnumerable<int> GetBigResultsAsync()
{
    
    await foreach (var result in GetResultsAsync())
    {
    
        if (result > 20) yield return result; 
    }
}

范围和下标类型(Ranges and indices)

C# 8.0 引入了 Index 类型,可用作数组下标,并且使用 ^ 操作符表示倒数。
不过要注意的是,倒数是从 1 开始的。

Index i1 = 3;  // 下标为 3
Index i2 = ^4; // 倒数第 4 个元素
int[] a = {
     0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
Console.WriteLine($"{
      a[i1]}, {
      a[i2]}"); // "3, 6"123123

除此之外,还引入了 “…” 操作符用来表示范围(注意是左闭右开区间)。

var slice = a[i1..i2]; // { 3, 4, 5 }

关于这个下标从 0 开始,倒数从 1 开始,范围左闭右开,笔者刚开始觉得很奇怪,但是发现 Python 等语言早已经做了这样的实践,并且效果不错。因此这次微软也采用了这种方式设计了 C# 8.0 的这个语法。

接口的默认实现方法(Default implementations of interface members)

从此接口中可以包含实现了:

interface ILogger
{
    
    void Log(LogLevel level, string message);
    void Log(Exception ex) => Log(LogLevel.Error, ex.ToString()); // 这是一个默认实现重载
}

class ConsoleLogger : ILogger
{
    
    public void Log(LogLevel level, string message) {
     ... }
    // Log(Exception) 会得到执行的默认实现
}

在上面的例子中,Log(Exception)将会得到执行的默认实现。

模式匹配表达式和递归模式语句(Switch expressions and recursive patterns)

现在可以这么写了(patterns 里可以包含 patterns)

IEnumerable<string> GetEnrollees()
{
    
    foreach (var p in People)
    {
    
        if (p is Student {
     Graduated: false, Name: string name }) yield return name;
    }
}

Student { Graduated: false, Name: string name }检查 p 是否为 Graduated = falseNamestringStudent,并且迭代返回 name
可以这样写之后是不是很爽?

更有:

var area = figure switch 
{
    
    Line _      => 0,
    Rectangle r => r.Width * r.Height,
    Circle c    => c.Radius * 2.0 * Math.PI,
    _           => throw new UnknownFigureException(figure)
};

典型的模式匹配语句,只不过没有用“match”关键字,而是沿用了
了“switch”关键字。
但是不得不说,一个字,爽!

目标类型推导(Target-typed new-expressions)

以前我们写下面这种变量/成员声明的时候,大概最简单的写法就是:

var points = new [] {
     new Point(1, 4), new Point(2, 6) };

private List<int> _myList = new List<int>();1212

现在我们可以这么写啦:

Point[] ps = {
     new (1, 4), new (3,-2), new (9, 5) };

private List<int> _myList = new ();1212

是不是更加的舒服了?

注意事项

该文章的最新版本已迁移至个人博客【比特飞】,单击链接 https://www.byteflying.com/archives/1037 访问。

  1. 以上的新特性需要 .NET Standard 2.1/.NET Core 3.0/.NET Framework 4.8 及以上来支持。
  2. 但是,由于接口的默认实现方法这个特性需要 CLR 的支持,而 .NET Framework 4.8 还没有来得及做出修改,因此此特性在 .NET Framework 4.8 中不可用,需要等待进一步的更新。
  3. C# 8.0 截至发文可以说已经定型了,正式发布还需要等一阵子。

一些想法

  1. 本次 C# 8.0 的更新,Record2估计是要被鸽了,有些小遗憾。
  2. C# 一直都在不断地完善和补充自己的语法体系,这和官方给出的 C# 发展目标相同,即:不断容纳各种优秀和现代的语法特性,追求多样化。相信这门优秀的语言未来会带给我们更多的惊喜。希望大家不要抱着老旧的看法对待这门语言,都 8012 年了我们也应该用全新的姿态去审视这门语言,去尝试一下新的语法对编码效率带来的大幅度提升。
  3. C# 的 IDE 除了 Visusl Studio 之外,还有 Visual Studio for Mac 以及跨平台的 Visual Studio Code、JetBrain 出品的 Rider 跨平台 C# IDE,极大程度的方便了开发者。
  4. 从近几年的发展来看,微软面对开源、生态建设、开发者、社区、跨平台等的重视程度不断上升,相信 .NET Core 的前景一定会更好。

参考文献


  1. https://blogs.msdn.microsoft.com/dotnet/2018/11/12/building-c-8-0
  2. https://github.com/dotnet/csharplang/issues/39
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_31116753/article/details/84147666

智能推荐

北京租房_weixin_34061555的博客-程序员宅基地

一、北京租房市场概况1. 区域特征西城、东城、朝阳、海淀为北京的四个核心区,适合年轻人及年轻人向往的工作机会多集中于这四个区,因此大多数在北京工作的年轻人工作地点都在这四个区内。环绕着这四个核心区依次为石景山、丰台、通州、昌平,这四个区可看作核心区的居住辐射区,许多在核心区工作的人会居住在其相应的配套区。以上八个区统称“城八区”,在某种意义上可以代表北京城的概念。这四个核心区及相应居住...

java玥显示_实验五 Java网络编程及安全 实验报告 20135232王玥_weixin_39562752的博客-程序员宅基地

北京电子科技学院(BESTI)实验报告课程:Java程序与设计 班级:1352姓名:王玥学号:20135232成绩: 指导教师:娄嘉鹏 实验日期:2015.6.9实验密级: 预习程度: 实验时间:15:30-18:00仪器组次: 必修/选修:选修 实验序号:5实验名称:Jav...

JAVA学习笔记Ⅹ——JAVA中的集合框架_DeepHao的博客-程序员宅基地

集合集合的数学定义:集合是指具有某种特定性质的具体的或抽象的对象汇总而成的集体。其中,构成集合的这些对象则称为该集合的元素,来源百度百科JAVA中集合定义:JAVA中集合是一种集合类,是一种工具,类似于容器,可以存储任意数量的具有共同属性的对象集合的作用:在类的内部对数据进行组织;简单而快速的搜索大量条目;有的集合接口,提供了一些列排列有序的元素,并且可以在序列中间快速的插入或删除有关元素;有的集合接口提供了映射关系,可以通过关键字(key)去快速查找到对应的唯一对象,而这个关键字可以是任意类型。集

radiobutton 选中的项不能去掉选择的问题_weixin_34126215的博客-程序员宅基地

 代码如下:RadioButton rbtn = new RadioButton(getApplicationContext()); rbtn.setText(String.valueOf(item.get(0))); rbtn.setTextSize(16); rbtn.setTag(Integer.parseInt(String.valueOf(item....

android emulator: ERROR: unknown virtual device name:解决方法_hy451176411的博客-程序员宅基地

<br />本人搞了一天,总算解决了:<br />  先说对这个问题的解决方法:设置一个环境变量名为:ANDROID_SDK_HOME,它的值设置为创建模拟器的路径,我的设为“C:/Users/Administrator/.android”,这个路径创建模拟器的路径,至于为何这么设,它默认去这里找吧,不过实际情况,得根据eclipse默认选择的情况,它默认选择在那里呢?可以在eclipse中再新建一个模拟器,可以在新建窗口上面会看到有一个“LIst of existing Android Virtual D

android回归linux主线,【进阶】从linux到android,历程的方方面面_一只小呆橘阿的博客-程序员宅基地

原文链接 : Anthony的简书博客最近在阅读《Linux内核设计与实现》,这里做一下linux中进程相关的知识点整理,以及android中进程的浅析。下面1,2小节整理自《Linux内核设计与实现》 第三章《进程管理》和第四章《进程调度》。第3节整理android中进程的知识点。1 Linux中的进程管理以下内容整理自:《Linux内核设计与实现》 第三章《进程管理》1.1进程和线程进程是资源...

随便推点

Ubuntu 17.10 将用 GDM 取代 LightDM 登录管理器_weixin_33845477的博客-程序员宅基地

在最近的一份报告中,Canonical 的 Will Cooke 透露,Ubuntu Desktop 团队正在考虑在即将推出的 Ubuntu 17.10 版本中以 GDM(GNOME显示管理器)取代 LightDM 登录管理器。本周早些时候已经有传闻表示 Ubuntu 17.10 将采用 GNOME GDM 显示管理器。特别是现在,在默认情况下,每日构建...

同时接收光栅和可搜索的PDF文件令人头疼?OCR简单处理!_weixin_45414340的博客-程序员宅基地

LEADTOOLS中的高级OCR SDK技术是多方面的,可以作为独立功能使用,也可以作为表单识别、支票识别和文档转换等更先进技术的驱动力。程序员自己可以编写三行代码来将图像转换为可搜索文本的文档。LEADTOOLS OCR Module - LEAD Engine(原Advantage Engine )增加了将光学字符识别(OCR)和智能字符识别(ICR)技术合并到应用程序中的一些方法,并且包...

安装多版本Python,一个神器足矣_未衬老师的博客-程序员宅基地

前言在Python开发中,有些情况下,我们可能面临在一台机器上同时安装多版本Python的需求。比如:有多个Python项目,每个项目依赖不同的Python版本。有一个Python项目,它需要同时支持多个Python版本。那么,如何高效地在单台机器上实现多个版本Python(具体来说,这里Python指的是Python解释器)的安装和维护呢?除此之外,我们还可能面临在一台机器上安装多...

使用VTK创建椭球_爱学习的北北的博客-程序员宅基地_vtk 椭圆

使用VTK创建椭球VTK中可以通过vtkParametricEllipsoid类与vtkParametricFunctionSource类协同作用创建一个椭球。介绍一下vtkParametricEllipsoid类。vtkParametricEllipsoid类继承自vtkParametricFunction类,其中我觉得常用的成员函数有:SetXRadius( double )SetYRadius( double )SetZRadius( double )三个函数分别用于设置椭球在X轴、Y轴

post.Comment.topic: (models.E006) The field ‘topic‘ clashes with the field ‘topic‘ from model ‘post._Caesar9646的博客-程序员宅基地

Django字段冲突解决项目文件class Topic(BaseModel): """ BBS的话题 """ title = models.CharField(max_length=255, unique=True, help_text='label of topics') content = models.TextField(help_text=u'content of topics') is_online = models.BooleanField(d

内存管理 - [ARC、AutoreleasePool]_Albert_YuHan的博客-程序员宅基地

问题出发我们知道,在面向对象编程中,每个对象都存在对应的构造函数和析构函数,当对象被创建和销毁时,构造、析构函数会被分别调用。对象从创建到销毁的整个过程,称之为对象的生命周期,为了保证在(1)使用对象时对象是有效的,没有被过早释放;(2)不需要使用对象时,对象被正常销毁而不是一直驻留在内存中,我们需要对象的生命周期进行管理。那么在iOS系统中,对象生命周期管理策略是怎样的呢?为了更好地逐步的了解iOS的内存管理机制,先抛出一些问题:(1)iOS使用引用计数来管理对象的生命周期,什么是引用计数?(2)