原文: Building C# 8.0

[译注:原文主标题如此,但内容大部分为新特性介绍,所以意译标题为 "C# 8.0 新特性"]

C# 的下一个主要版本是 8.0。我们已经为它工作了很长一段时间,即使我们构建并发布了次要版本 C# 7.1, 7.2 和 7.3,我仍然对 8.0 将带来的新特性感到非常兴奋。

目前的计划是 C# 8.0 将与 .NET Core 3.0 同时发布。然而,随着我们正在开发的 Visual Studio 2019 的预览版,这些特性将开始活跃起来。当这些出来的时候,您就可以开始尝试它们,我们将提供有关各个特性的更多细节。这篇文章的目的是向您简述预期的内容,以及如何理解它们。

C# 8.0 新特性

下面是 C# 8.0 中最重要的新特性的概述。还有一些较小的改进正在进行中,这些改进将在未来几个月逐渐显现出来。

Nullable reference types 可空引用类型

此特性的目的是帮助处理无处不在的空引用异常,这种异常已经困扰了半个世纪的面向对象编程。

这个特性阻止您将 null 放入普通引用类型中(如字符串),从而使这些类型不可为 null!不过它是温和的提示警告,而不是错误。所以,它会让现有代码出现新的警告,因此您必须有选择的使用该功能 (您可以在项目、文件甚至行级别执行此操作)。

string s = null; // Warning: Assignment of null to non-nullable reference type

如果您确实想要 null 怎么办?可以使用一个可空引用类型,例如 string? 这样:

string? s = null; // Ok

当您尝试使用可空引用类型时,你首先需要检查是否为空。编译器会分析代码流,以查看 null 值是否可以将其用于当前位置:

void M(string? s)
{
Console.WriteLine(s.Length); // Warning: Possible null reference exception
if (s != null)
{
Console.WriteLine(s.Length); // Ok: You won't get here if s is null
}
}

这个特性的要点是,C# 允许您表达“可空的意图”,并且在您不遵守它时候发出警告。

Async streams 异步流

C# 5.0 的 async/await 特性使您可以用非常简单的代码消费(或生产)异步结果, 而无需回调:

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

如果您想要消费(或生产)连续的结果流(例如您可能从物联网设备或云服务获得),则没有那么有用。 异步流就是为此而存在的。

如果您想要消费(或生产)连续的结果流(例如您可能从物联网设备或云服务获得),则没有那么有用。 异步流就是为此而存在的。

我们现在介绍一下您所期望的 IAsyncEnumerable<T>,即 IEnumerable<T> 的异步版本。允许您 await foreach 以消费它们的元素,并 yield return 以生产元素。

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

Ranges and indices 范围和索引

我们正在添加一个类型 Index,可用于索引。您可以创建一个整型来表示从头开始的索引,或者一个 ^ 前缀的从结尾表示的索引:

Index i1 = 3;  // number 3 from beginning
Index i2 = ^4; // number 4 from end
int[] a = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
Console.WriteLine($"{a[i1]}, {a[i2]}"); // "3, 6"

我们还引入了一个 Range 类型,它由两个 Index 组成,一个用于开始,一个用于结束,并且可以用 x..y 这样的范围表达式来编写。然后,您可以使用 Range 进行索引来生成切片:

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

Default implementations of interface members 接口成员的默认实现

现在,一旦你发布了一个接口,游戏就结束了:你不能在不破坏它的所有现有实现的情况下向它添加成员。

在 C# 8.0 中,我们允许您为接口成员提供一个默认实现。因此,如果某人没有实现该成员(可能因为他们编写代码时还没有该成员),他们将只得到默认的实现。

interface ILogger
{
void Log(LogLevel level, string message);
void Log(Exception ex) => Log(LogLevel.Error, ex.ToString()); // New overload
} class ConsoleLogger : ILogger
{
public void Log(LogLevel level, string message) { ... }
// Log(Exception) gets default implementation
}

ConsoleLogger 类不必实现 ILogger 中 Log(Exception) 重载函数,因为它已经定义了默认实现。现在只要提供了一个默认实现,您就可以添加新的成员到已经存在的公开接口中了。

Recursive 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 } 会检查 Person 是否是 Student,然后将常量模式 false 应用于 Graduated 属性以查看它们是否已毕业,并将模式字符串 name 添加到其 Name 属性中,得到他们的名字(如果非空)。因此,如果 p 是 Student,没有毕业并且具有非空的名字,则返回该名字。

Switch expressions Switch 表达式

带有模式的 switch 语句在 C# 7.0 中非常强大,但编写起来很麻烦。switch 表达式是一个“轻量级”版本,其中所有情况都是表达式:

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

Target-typed new-expressions 已知目标类型的新表达式

在许多情况下,当您创建新对象时,类型已经可以从上下文中知道。在这些情况下,可以省略类型:

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

该功能的实现由社区成员提供,谢谢!

平台依赖性

大多数 C# 8.0 语言特性都可以在任何版本的 .NET 上运行。但是,其中一些具有平台依赖性。

Async streams, Index 和 Range 都依赖于 .NET Standard 2.1 的新类型。正如 Immo 在他的文章《公布.NET Standard 2.1》所说的那样,.NET Core 3.0 、Xamarin 、Unity 和 Mono 都将实现 .NET Standard 2.1,但 .NET Framework 4.8 不会。这意味着当您将 C# 8.0 指向到 .NET Framework 4.8 时,使用这些功能所需的类型将不可用。

与往常一样,C# 编译器对它所依赖的类型非常宽容。如果它能找到具有正确的名字和形态的类型,则很乐意将它们作为目标。

默认接口实现依赖于新的增强运行时,我们也不会在 .NET Runtime 4.8 中实现这些。因此,此特性不适用于 .NET Framework 4.8 和旧版本的 .NET。

十余年间,为了保持运行时的稳定,我们无法在其中实现新的语言特性。随着现代化运行时的并行性和开源性,我们觉得可以负责任地去重新开发它们,并在考虑到这一点时进行语言设计。 Scott 在其 .NET Core 3.0 和 .NET Framework 4.8 更新中解释说,.NET Framework 将来会看到较少的创新,而是关注稳定性和可靠性。考虑到这一点,我们认为,直接忽略某些语言特性会好一些。

想要了解更多?

C# 语言的设计过程是开源的,在这个repo中。如果您不经常跟进,可能会有点混乱和力不从心。语言设计的核心是语言设计会议,记录在 C# 语言设计日记

大约一年前,我写了一篇介绍C#中的可空引用类型的文章。您仍然可以阅读它并得到一些信息。。

您还可以观看视频,例如 Microsoft Build 2018 大会上的 C# 未来,或者 .NET Conf 2018 大会上的即将到来的 C#,它展示了其中一些特性。

Kathleen 有一篇很好的帖子来阐述了 .Net Core 3.0 中的 Visual Basic 的计划。

当我们开始将这些功能作为 Visual Studio 2019 预览版的一部分发布时,我们还将发布有关各个功能的更多详细信息。

就个人而言,我迫不及待地要把它们交到你们所有人手中!

Happy hacking,

Mads Torgersen, Design Lead for C#

[翻译] C# 8.0 新特性的更多相关文章

  1. [翻译] C# 8.0 新特性 Redis基本使用及百亿数据量中的使用技巧分享(附视频地址及观看指南) 【由浅至深】redis 实现发布订阅的几种方式 .NET Core开发者的福音之玩转Redis的又一傻瓜式神器推荐

    [翻译] C# 8.0 新特性 2018-11-13 17:04 by Rwing, 1179 阅读, 24 评论, 收藏, 编辑 原文: Building C# 8.0[译注:原文主标题如此,但内容 ...

  2. C# 7.0 新特性4: 返回引用

    本文参考Roslyn项目中的Issue:#118. 1. C# 7.0 新特性1: 基于Tuple的“多”返回值方法 2. C# 7.0 新特性2: 本地方法 3. C# 7.0 新特性3: 模式匹配 ...

  3. c# 6.0新特性(一)

    写在前面 接近年底了,基本上没什么活了,就学点新东西,就想着了解下c# 6.0的新特性.在code project上看到了一篇不错的文章,就准备翻译一下,顺便照着学习学习.废话不多说,直奔主题. 原文 ...

  4. AFNetworking 2.0 新特性讲解之AFHTTPSessionManager

    AFNetworking 2.0 新特性讲解之AFHTTPSessionManager (2014-02-17 11:56:24) 转载▼     AFNetworking 2.0 相比1.0 API ...

  5. C#5.0新特性

    C#5.0新特性 C#5.0最大的新特性,莫过于Async和Parallel. 以往我们为了让用户界面保持相应,我们可以直接使用异步委托或是System.Threading命名空间中的成员,但Syst ...

  6. C# 7.0 新特性:本地方法

    C# 7.0:本地方法 VS 2017 的 C# 7.0 中引入了本地方法,本地方法是一种语法糖,允许我们在方法内定义本地方法.更加类似于函数式语言,但是,本质上还是基于面向对象实现的. 1. 本地方 ...

  7. Atitit spring 3.0 3.1 3.2 4.0 4.3 5.0 新特性

    Atitit spring 3.0 3.1 3.2 4.0 4.3 5.0 新特性 Spring3.0的新特性及其分析 - 我的人生不甘于平庸! - ITeye技术网站.html Spring3.0带 ...

  8. C# 9.0新特性

    CandidateFeaturesForCSharp9 看到标题,是不是认为我把标题写错了?是的,C# 8.0还未正式发布,在官网它的最新版本还是Preview 5,通往C#9的漫长道路却已经开始.前 ...

  9. C# 9.0 新特性预览 - 空参数校验

    C# 9.0 新特性预览 - 空参数校验 前言 随着 .NET 5 发布日期的日益临近,其对应的 C# 新版本已确定为 C# 9.0,其中新增加的特性(或语法糖)也已基本锁定,本系列文章将向大家展示它 ...

随机推荐

  1. 添加用户到sudoers

    ** is not in the sudoersfile.  This incident will bereported.” (用户不在sudoers文件中……) 处理这个问题很简单,但应该先理解其原 ...

  2. 机器学习之EM算法(五)

    摘要 EM算法全称为Expectation Maximization Algorithm,既最大期望算法.它是一种迭代的算法,用于含有隐变量的概率参数模型的最大似然估计和极大后验概率估计.EM算法经常 ...

  3. Sqlserver还原master

    net stop mssqlserver net start mssqlserver /m"SQLCMD" sqlcmd -s xx sqlcmd -s xx -U sa -P x ...

  4. c/c++ 深拷贝

    解决上一篇浅拷贝的问题 浅拷贝的问题根源是,类里有指针类型的成员变量,所以需要自己编写拷贝构造函数和重载=函数 #include <iostream> #include <strin ...

  5. Can We Make Operating Systems Reliable and Secure?

    Andrew S. Tanenbaum, Jorrit N. Herder, and Herbert Bos Vrije Universiteit, Amsterdam Microkernels-lo ...

  6. Visio画图--我的形状

    本人用的Visio 2013 打开Visio后新建一个拓扑图,发现左侧形状一栏不见了 形状栏可以保存很多自定义图形,怎么才能将形状一栏重新显示出来呢?方法其实很简单,方法如下所示: 这时候我们就会发现 ...

  7. March 09th, 2018 Week 10th Friday

    All good things must come to an end. 好景无常. Love is when the other person's happiness is more importa ...

  8. 为什么react的组件要super(props)

    https://segmentfault.com/q/1010000008340434

  9. linux下安装jdk_mysql_tomcat_redis

    目前搬我以前的笔记,每个人做笔记方式都不一样,看别人的风格,生成自己的风格 1.linux安装软件和redis学习 jdk --- java开发运行环境 Tomcat - WEB程序的服务器 Mysq ...

  10. Md5的生成

    1.使用hashlib包(一) import hashlib src = 'anthing' m1 = hash.new() m1.update(src) print (m1.hexdigest()) ...