25

VS 2019 要来了,是时候了解一下 C# 8.0 新功能

 5 years ago
source link: https://www.infoq.cn/article/1Req7bENeXzy71ckX*X6?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

近日,微软发布了 Visual Studio 2019 的发布日期,2019 年 4 月 2 日 Visual Studio 2019 将正式和大家见面,同时微软还将提供发布现场实时直播。

除了 Visual Studio 2019 自身之外,VS 2019 的发布还牵动着很多 C# 开发者的心。虽然一个月之前发布的 Visual Studio 2019 Preview 版本已经可以试用 C# 的某些新功能,但还有一些是不可试用的。

下面我们就来看一下微软官方对 C#8.0 重要功能的概述。

可空的引用类型

此功能的目的是防止无处不在的空引用异常,空引用异常已经困扰面向对象编程半个世纪了。该功能将阻止开放者将 null 值放入到普通的引用类型中,例如 String 类型不可为空。但它不是强制性的 error,而是比较温和的 warning。

这些异常现在已经过了半个世纪的面向对象编程。

它阻止你 null 进入普通的引用类型,例如 string- 它使这些类型不可为空!它是温和的,有警告,而不是错误。但是在现有代码上会出现新警告,因此您必须选择使用该功能(您可以在项目,文件甚至源代码级别执行此功能)。

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

如果你想要使用 null 怎么 ?可以使用 空的引用类型 ,例如 string?:

string? s = null; // Ok

当你使用了可空引用时,需要先检查一下其是否为 null,编译器会分析代码流,以查看 null 值是否可以将其用于您使用它的位置:

复制代码

voidM(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# 允许表达可空的意图,但是在不遵守规则时会发出警告。

异步流

C#5.0 的 async / await 功能允许在简单的代码中使用(并生成)异步结果,而无需回调:

复制代码

asyncTask<int>GetBigResultAsync()
{
varresult =awaitGetResultAsync();
if(result >20)returnresult;
elsereturn-1;
}

下面我们来介绍一下大家期待已久的 IAsyncEnumerable , 异步版本的 IEnumerable 。该语言允许 await foreach 使用元素,并使用 yield return 生成元素。

复制代码

asyncIAsyncEnumerable<int>GetBigResultsAsync()
{
awaitforeach(varresultinGetResultsAsync())
{
if(result >20)yieldreturnresult;
}
}

范围和索引

我们正在添加一个可用于索引的 Index 类型。你可以使用 int 从头创建,也可以使用 ^ 从末尾开始计算前缀运算符:

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 类型,它由两个 Indexes 组成,一个用于开始,一个用于结束,并且可以用 x…y  范围表达式 编写。

可以使用 a 进行索引 Range 以生成切片:

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

接口成员的默认实现

今天,大家对于界面都有这样一个需求:在不破坏现有状态的情况下添加一个成员。

在 C#8.0 中,我们会为接口成员提供一个主体。如果有人没有实现该成员(或者是在编写代码时还没有实现),会获得默认实现。

复制代码

interfaceILogger
{
voidLog(LogLevel level,stringmessage);
voidLog(Exception ex) => Log(LogLevel.Error, ex.ToString());// New overload
}

classConsoleLogger:ILogger
{
publicvoidLog(LogLevel level,stringmessage) { ... }
// Log(Exception) gets default implementation
}

在 ConsoleLogger 类不需要实现 ILogger 的 Log(Exception) 重载,因为它已经默认实现了。现在只要给当前实现者提供了默认实现,就可以向现有公共接口添加新成员。

递归模式

我们允许 pattern 中包含其他 pattern:

复制代码

IEnumerable<string>GetEnrollees()
{
foreach(varpinPeople)
{
if(pisStudent { Graduated:false, Name:stringname })yieldreturnname;
}
}

pattern Student { Graduated: false, Name: string name }主要检查 Person 是 a Student,然后将常量 pattern false 应用于其 Graduated 属性以查看它们是否仍然已注册,并将 pattern string name 应用于其 Name 属性以获取其名称(如果为非 null)。因此,如果 p 是一个 Student,尚未毕业并且姓名非空,那么我们就可以 yield return 这个名字。

Switch 表达式

带有 pattern 的 switch 语句在 C#7.0 中已经非常强大了,但是编写起来却很麻烦,而 Switch 表达式却是一个解决这种问题的、“轻量级”的版本。

复制代码

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

目标类型的新表达式

在许多情况下,往往创建新对象时,类型已经从上下文中给出。在这些情况下,我们会让你省略类型:

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

C# 大版本关键更新回顾

C#1.0(Visual Studio .NET)

  • Classes
  • Structs
  • Interfaces
  • Events
  • Properties
  • Delegates
  • Expressions
  • Statements
  • Attributes
  • Literal

C#2(VS 2005)

  • Generics
  • Partial types
  • Anonymous methods
  • Iterators
  • Nullable types
  • Getter/setter separate accessibility
  • Method group conversions (delegates)
  • Static classes
  • Delegate inferenc

C#3(VS 2008)

  • Implicitly typed local variables
  • Object and collection initializers
  • Auto-Implemented properties
  • Anonymous types
  • Extension methods
  • Query expressions
  • Lambda expression
  • Expression trees
  • Partial methods

C#4(VS 2010)

  • Dynamic binding
  • Named and optional arguments
  • Co- and Contra-variance for generic delegates and interfaces
  • Embedded interop types (“NoPIA”

C#5(VS 2012)

  • Asynchronous methods
  • Caller info attributes

C#6(VS 2015)

  • Draft Specification online
  • Compiler-as-a-service (Roslyn)
  • Import of static type members into namespace
  • Exception filters
  • Await in catch/finally blocks
  • Auto property initializers
  • Default values for getter-only properties
  • Expression-bodied members
  • Null propagator (null-conditional operator, succinct null checking)
  • String interpolation
  • nameof operator
  • Dictionary initializer

C#7.0(Visual Studio 2017)

平台依赖

大多数的 C# 8.0 功能都可以在任何版本的.NET 上运行,但也有一些功能是有平台依赖性的,例如异步流、范围和索引都依赖 .NET Standard 2.1 一部分的新框架类型。其中,.NET Standard 2.1、.NET Core 3.0 以及 Xamarin,Unity 和 Mono 都将实现 .NET Standard 2.1, 而.NET Framework 4.8 不会,所以如果你使用的是 .NET Framework 4.8,那么 C# 8.0 的部分功能可能不能使用。

另外,接口成员的默认实现也依赖新的运行时增强功能,所以此功能也不适用于 .NET Framework 4.8 和旧版本的 .NET。

微软官方博客链接: https://blogs.msdn.microsoft.com/dotnet/2018/11/12/building-c-8-0/


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK