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

\u003cp\u003e近日,微软发布了Visual Studio 2019 的发布日期,2019年4月2日Visual Studio 2019 将正式和大家见面,同时微软还将提供发布现场实时直播。\u003c/p\u003e\n\u003cp\u003e除了Visual Studio 2019自身之外,VS 2019的发布还牵动着很多C#开发者的心。虽然一个月之前发布的Visual Studio 2019 Preview版本已经可以试用C#的某些新功能,但还有一些是不可试用的。\u003c/p\u003e\n\u003cp\u003e下面我们就来看一下微软官方对C#8.0重要功能的概述。\u003c/p\u003e\n\u003ch2\u003e可空的引用类型\u003c/h2\u003e\n\u003cp\u003e此功能的目的是防止无处不在的空引用异常,空引用异常已经困扰面向对象编程半个世纪了。该功能将阻止开放者将null值放入到普通的引用类型中,例如String类型不可为空。但它不是强制性的error,而是比较温和的warning。\u003c/p\u003e\n\u003cp\u003e这些异常现在已经过了半个世纪的面向对象编程。\u003cbr /\u003e\n它阻止你null进入普通的引用类型,例如string- 它使这些类型不可为空!它是温和的,有警告,而不是错误。但是在现有代码上会出现新警告,因此您必须选择使用该功能(您可以在项目,文件甚至源代码级别执行此功能)。\u003cbr /\u003e\nstring s = null; // Warning: Assignment of null to non-nullable reference type\u003cbr /\u003e\n如果你想要使用null怎么\u003cem\u003e办\u003c/em\u003e?可以使用\u003cem\u003e可\u003c/em\u003e为\u003cem\u003e空的引用类型\u003c/em\u003e,例如string?:\u003cbr /\u003e\nstring? s = null; // Ok\u003cbr /\u003e\n当你使用了可空引用时,需要先检查一下其是否为null,编译器会分析代码流,以查看null值是否可以将其用于您使用它的位置:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003evoid M(string? s)\n{\n Console.WriteLine(s.Length); // Warning: Possible null reference exception\n if (s != null)\n {\n Console.WriteLine(s.Length); // Ok: You won't get here if s is null\n }\n}\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eC#允许表达可空的意图,但是在不遵守规则时会发出警告。\u003c/p\u003e\n\u003ch2\u003e异步流\u003c/h2\u003e\n\u003cp\u003eC#5.0的async / await功能允许在简单的代码中使用(并生成)异步结果,而无需回调:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003easync Task\u0026lt;int\u0026gt; GetBigResultAsync()\n{\n var result = await GetResultAsync();\n if (result \u0026gt; 20) return result; \n else return -1;\n}\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e下面我们来介绍一下大家期待已久的IAsyncEnumerable\u003cT\u003e, 异步版本的IEnumerable\u003cT\u003e。该语言允许await foreach使用元素,并使用yield return生成元素。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003easync IAsyncEnumerable\u0026lt;int\u0026gt; GetBigResultsAsync()\n{\n await foreach (var result in GetResultsAsync())\n {\n if (result \u0026gt; 20) yield return result; \n }\n}\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch2\u003e范围和索引\u003c/h2\u003e\n\u003cp\u003e我们正在添加一个可用于索引的Index类型。你可以使用int从头创建,也可以使用^从末尾开始计算前缀运算符:\u003cbr /\u003e\nIndex i1 = 3; // number 3 from beginning\u003cbr /\u003e\nIndex i2 = ^4; // number 4 from end\u003cbr /\u003e\nint[] a = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };\u003cbr /\u003e\nConsole.WriteLine($\u0026quot;{a[i1]}, {a[i2]}\u0026quot;); // “3, 6”\u003cbr /\u003e\n另外,我们还引入了一个Range类型,它由两个Indexes 组成,一个用于开始,一个用于结束,并且可以用x…y \u003cem\u003e范围表达式\u003c/em\u003e编写。\u003cbr /\u003e\n可以使用a进行索引Range以生成切片:\u003cbr /\u003e\nvar slice = a[i1…i2]; // { 3, 4, 5 }\u003c/p\u003e\n\u003ch2\u003e接口成员的默认实现\u003c/h2\u003e\n\u003cp\u003e今天,大家对于界面都有这样一个需求:在不破坏现有状态的情况下添加一个成员。\u003c/p\u003e\n\u003cp\u003e在C#8.0中,我们会为接口成员提供一个主体。如果有人没有实现该成员(或者是在编写代码时还没有实现),会获得默认实现。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003einterface ILogger\n{\n void Log(LogLevel level, string message);\n void Log(Exception ex) =\u0026gt; Log(LogLevel.Error, ex.ToString()); // New overload\n}\n\nclass ConsoleLogger : ILogger\n{\n public void Log(LogLevel level, string message) { ... }\n // Log(Exception) gets default implementation\n}\n\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e在ConsoleLogger类不需要实现ILogger的Log(Exception)重载,因为它已经默认实现了。现在只要给当前实现者提供了默认实现,就可以向现有公共接口添加新成员。\u003c/p\u003e\n\u003ch2\u003e递归模式\u003c/h2\u003e\n\u003cp\u003e我们允许pattern中包含其他pattern:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003eIEnumerable\u0026lt;string\u0026gt; GetEnrollees()\n{\n foreach (var p in People)\n {\n if (p is Student { Graduated: false, Name: string name }) yield return name;\n }\n}\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003epattern Student { Graduated: false, Name: string name }主要检查Person是a Student,然后将常量pattern false应用于其Graduated属性以查看它们是否仍然已注册,并将pattern string name应用于其Name属性以获取其名称(如果为非null)。因此,如果p是一个Student,尚未毕业并且姓名非空,那么我们就可以yield return这个名字。\u003c/p\u003e\n\u003ch2\u003eSwitch表达式\u003c/h2\u003e\n\u003cp\u003e带有pattern的switch语句在C#7.0中已经非常强大了,但是编写起来却很麻烦,而Switch 表达式却是一个解决这种问题的、“轻量级”的版本。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003evar area = figure switch \n{\n Line _ =\u0026gt; 0,\n Rectangle r =\u0026gt; r.Width * r.Height,\n Circle c =\u0026gt; Math.PI * c.Radius * c.Radius,\n _ =\u0026gt; throw new UnknownFigureException(figure)\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch2\u003e目标类型的新表达式\u003c/h2\u003e\n\u003cp\u003e在许多情况下,往往创建新对象时,类型已经从上下文中给出。在这些情况下,我们会让你省略类型:\u003cbr /\u003e\nPoint[] ps = { new (1, 4), new (3,-2), new (9, 5) }; // all Points\u003c/p\u003e\n\u003ch2\u003eC#大版本关键更新回顾\u003c/h2\u003e\n\u003cp\u003eC#1.0(Visual Studio .NET)\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eClasses\u003c/li\u003e\n\u003cli\u003eStructs\u003c/li\u003e\n\u003cli\u003eInterfaces\u003c/li\u003e\n\u003cli\u003eEvents\u003c/li\u003e\n\u003cli\u003eProperties\u003c/li\u003e\n\u003cli\u003eDelegates\u003c/li\u003e\n\u003cli\u003eExpressions\u003c/li\u003e\n\u003cli\u003eStatements\u003c/li\u003e\n\u003cli\u003eAttributes\u003c/li\u003e\n\u003cli\u003eLiteral\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eC#2(VS 2005)\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eGenerics\u003c/li\u003e\n\u003cli\u003ePartial types\u003c/li\u003e\n\u003cli\u003eAnonymous methods\u003c/li\u003e\n\u003cli\u003eIterators\u003c/li\u003e\n\u003cli\u003eNullable types\u003c/li\u003e\n\u003cli\u003eGetter/setter separate accessibility\u003c/li\u003e\n\u003cli\u003eMethod group conversions (delegates)\u003c/li\u003e\n\u003cli\u003eStatic classes\u003c/li\u003e\n\u003cli\u003eDelegate inferenc\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eC#3(VS 2008)\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eImplicitly typed local variables\u003c/li\u003e\n\u003cli\u003eObject and collection initializers\u003c/li\u003e\n\u003cli\u003eAuto-Implemented properties\u003c/li\u003e\n\u003cli\u003eAnonymous types\u003c/li\u003e\n\u003cli\u003eExtension methods\u003c/li\u003e\n\u003cli\u003eQuery expressions\u003c/li\u003e\n\u003cli\u003eLambda expression\u003c/li\u003e\n\u003cli\u003eExpression trees\u003c/li\u003e\n\u003cli\u003ePartial methods\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eC#4(VS 2010)\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eDynamic binding\u003c/li\u003e\n\u003cli\u003eNamed and optional arguments\u003c/li\u003e\n\u003cli\u003eCo- and Contra-variance for generic delegates and interfaces\u003c/li\u003e\n\u003cli\u003eEmbedded interop types (“NoPIA”\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eC#5(VS 2012)\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eAsynchronous methods\u003c/li\u003e\n\u003cli\u003eCaller info attributes\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eC#6(VS 2015)\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/dotnet/csharplang/blob/master/spec/README.md\"\u003eDraft Specification online\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003eCompiler-as-a-service (Roslyn)\u003c/li\u003e\n\u003cli\u003eImport of static type members into namespace\u003c/li\u003e\n\u003cli\u003eException filters\u003c/li\u003e\n\u003cli\u003eAwait in catch/finally blocks\u003c/li\u003e\n\u003cli\u003eAuto property initializers\u003c/li\u003e\n\u003cli\u003eDefault values for getter-only properties\u003c/li\u003e\n\u003cli\u003eExpression-bodied members\u003c/li\u003e\n\u003cli\u003eNull propagator (null-conditional operator, succinct null checking)\u003c/li\u003e\n\u003cli\u003eString interpolation\u003c/li\u003e\n\u003cli\u003enameof operator\u003c/li\u003e\n\u003cli\u003eDictionary initializer\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eC#7.0(Visual Studio 2017)\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.0/out-var.md\"\u003eOut variables\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/dotnet/csharplang/blob/master/proposals/patterns.md\"\u003ePatt\u003c/a\u003e\u003ca href=\"https://github.com/dotnet/csharplang/blob/master/proposals/patterns.md\"\u003eern matching\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/dotnet/roslyn/blob/master/docs/features/tuples.md\"\u003eTup\u003c/a\u003e\u003ca href=\"https://github.com/dotnet/roslyn/blob/master/docs/features/tuples.md\"\u003eles\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/dotnet/roslyn/blob/master/docs/features/deconstruction.md\"\u003eD\u003c/a\u003e\u003ca href=\"https://github.com/dotnet/roslyn/blob/master/docs/features/deconstruction.md\"\u003eeconst\u003c/a\u003e\u003ca href=\"https://github.com/dotnet/roslyn/blob/master/docs/features/deconstruction.md\"\u003eruc\u003c/a\u003e\u003ca href=\"https://github.com/dotnet/roslyn/blob/master/docs/features/deconstruction.md\"\u003etion\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/dotnet/roslyn/blob/master/docs/features/discards.md\"\u003eDiscards\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.0/local-functions.md\"\u003eLoc\u003c/a\u003e\u003ca href=\"https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.0/local-functions.md\"\u003eal Funct\u003c/a\u003e\u003ca href=\"https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.0/local-functions.md\"\u003eion\u003c/a\u003e\u003ca href=\"https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.0/local-functions.md\"\u003es\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.0/binary-literals.md\"\u003eBinary Litera\u003c/a\u003e\u003ca href=\"https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.0/binary-literals.md\"\u003els\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.0/digit-separators.md\"\u003eDi\u003c/a\u003e\u003ca href=\"https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.0/digit-separators.md\"\u003egit Separators\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003eRef returns and locals\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/dotnet/roslyn/blob/master/docs/features/task-types.md\"\u003eGener\u003c/a\u003e\u003ca href=\"https://github.com/dotnet/roslyn/blob/master/docs/features/task-types.md\"\u003ealized async return ty\u003c/a\u003e\u003ca href=\"https://github.com/dotnet/roslyn/blob/master/docs/features/task-types.md\"\u003epes\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003eMore expression-bodied members\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.0/throw-expression.md\"\u003eThro\u003c/a\u003e\u003ca href=\"https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.0/throw-expression.md\"\u003ew express\u003c/a\u003e\u003ca href=\"https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.0/throw-expression.md\"\u003eions\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2\u003e平台依赖\u003c/h2\u003e\n\u003cp\u003e大多数的C# 8.0功能都可以在任何版本的.NET上运行,但也有一些功能是有平台依赖性的,例如异步流、范围和索引都依赖 .NET Standard 2.1一部分的新框架类型。其中,.NET Standard 2.1、.NET Core 3.0以及Xamarin,Unity和Mono都将实现 .NET Standard 2.1,\u003ca href=\"http://xn--6w0a.NET\"\u003e而.NET\u003c/a\u003e Framework 4.8不会,所以如果你使用的是 .NET Framework 4.8,那么C# 8.0的部分功能可能不能使用。\u003c/p\u003e\n\u003cp\u003e另外,接口成员的默认实现也依赖新的运行时增强功能,所以此功能也不适用于 .NET Framework 4.8和旧版本的 .NET。\u003c/p\u003e\n\u003cp\u003e微软官方博客链接:\u003ca href=\"https://blogs.msdn.microsoft.com/dotnet/2018/11/12/building-c-8-0/\"\u003ehttps://blogs.msdn.microsoft.com/dotnet/2018/11/12/building-c-8-0/\u003c/a\u003e\u003c/p\u003e\n
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值