准备工做: html
Visual Studio 2019 Preview版本中并无包含全部的C# 8.0的新功能,但目前也有一些能够试用了。在开始以前,须要进行入两项设置:git
也能够直接编辑.csproj文件,修改TargetFramework和LangVersion为以下形式:程序员
<TargetFramework>netcoreapp3.0</TargetFramework>
<LangVersion>8.0</LangVersion> github
Nullable reference types 编程
空引用对于全部编程者来讲相信都是一个很是头痛的问题,图灵奖得主Tony Hoare 就把包含空引用的编程语言用定义为一个十亿美圆的错误Null References: The Billion Dollar Mistake。 c#
首先仍是来一段简单的代码: 数组
string s = null;
Console.WriteLine($"The first letter of {s} is {s[0]}"); app
这段代码编译没有问题,但运行的时候会抛空引用异常的。 异步
在C# 8.0中,开启了空引用异常检测后,上述代码在编译器就会检查出告警来。 socket
而且它会结合上下文判断,若是该值不会为null,则不会告警,很是智能。
细心的朋友可能会发现,虽然在下面使用的地方没有告警,可是变量初始化的地方仍是报告警了。若是咱们的程序自己就是容许null值改怎么办呢,听任告警无论也是不合适的作法。
针对这个问题,C#引入了一个新的声明为可空对象的语法:
string? s = null;
也就是在类型后加一个?符号,表面该对象是一个可空对象。
因为这个行为和以前的C#版本是不一致的,所以默认是没有开启这个功能的,咱们须要在csproj文件中打开这个设置:
<LangVersion>8.0</LangVersion>
<NullableReferenceTypes>true</NullableReferenceTypes>
不知道在后续的VS的版本中会不会直接再界面上添加这一设置。
最后总结一下,Nullable reference types主要干了两件事:
虽然以前有一些第三方插件也集成了相似的功能,如Resharper的Null Check,但把这个功能集成到了编译器上后更加简洁好用。
C#的空对象检查在设计期间也有好几种语法方案,目前这种方案既解决了问题,又对现有代码保持彻底兼容,还能对现有代码潜在性问题能进行分析,是一种比较理想的方案的。若是之后能经过设置,将空引用的告警级别能够设置为错误就更好了。
Ranges and indices
范围和索引是C#新引入的语法,它主要引入了两个对象Range和Index。
Index
首先仍是来看一个简单的例子。
var numbers = new[] { 1, 2, 3, 4, 5, 6, 7 };
Index i1 = 3; // number 3 from beginning
Index i2 = ^2; // number 2 from end
Console.WriteLine($"{numbers[i1]}, {numbers[i2]}"); // "4, 6"
这个例子简单的演示了一下Index的用法,Index自己仍是相似于以前的int索引的,它也能够和int类型转换。但Index在int索引的方式扩展了一下,支持从后往前访问,也就是咱们说的倒数位。
Index i2 = ^2; // number 2 from end
Range
基于Index组成起点和终点,能够组成了一个范围Range,根据Range能够对数组进行切片。
Range range = Range.Create(i1, i2);
int[] slice = numbers[range]; //"4, 5"
".."运算符
为了快速表示一个Range,C#还映入了一个新的运算符".."如上面的代码就能够简写为:
int[] slice = numbers[i1..i2]; //"4, 5"
".."语法不复杂,经过".."链接的开头和结尾的索引,用来表示一个范围。为了使用方便,".."运算符的开头和结尾是能够省略的,经常使用的大体就有这几种形式。
string text = "hello c# 8.0";
Console.WriteLine(text[..]); //"hello c# 8.0"
Console.WriteLine(text[^3..]); //"8.0"
Console.WriteLine(text[..5]); //"hello"
Console.WriteLine(text[6..]); //"c# 8.0"
经过".."运算符,咱们描述切片时能够清晰不少,例如以下这个常见的求字符串子串的例子:
var sub = text.Substring(text.Length - 6, 6);
var sub2 = text[^6..];
.net 3.0的不少类都内置了对Range的切片操做,常见的有:
Asynchronous streams
异步流能一种拉的方式进行异步迭代,配合async编程能够以异步的方式把socket流像本地文件同样解析,相信这是不少用c#写socket程序的程序员所喜欢的一个特性。
一个简单的示例以下:
static async IAsyncEnumerable<string> GetNamesAsync()
{
await Task.Delay(1000);
yield return "hello";
await Task.Delay(1000);
yield return "world";
}
await foreach (var name in GetNamesAsync())
{
Console.WriteLine(name);
}
我在Visual Studio 2019 preview中试用这个功能的时候,发现没法编译经过。MS解释说这个是VS和.net core代码没有彻底匹配上所致,咱们能够手动添加相关代码以完成这一编译过程。
namespace System.Threading.Tasks { using System.Runtime.CompilerServices; using global::System.Threading.Tasks.Sources; internal struct ManualResetValueTaskSourceLogic<TResult> { private ManualResetValueTaskSourceCore<TResult> _core; public ManualResetValueTaskSourceLogic(IStrongBox<ManualResetValueTaskSourceLogic<TResult>> parent) : this() { } public short Version => _core.Version; public TResult GetResult(short token) => _core.GetResult(token); public ValueTaskSourceStatus GetStatus(short token) => _core.GetStatus(token); public void OnCompleted(Action<object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags) => _core.OnCompleted(continuation, state, token, flags); public void Reset() => _core.Reset(); public void SetResult(TResult result) => _core.SetResult(result); public void SetException(Exception error) => _core.SetException(error); } } namespace System.Runtime.CompilerServices { internal interface IStrongBox<T> { ref T Value { get; } } }
其余语法
自己C# 8.0是还有几个其它语法的,如接口默认方法,高级模式匹配等。这些语法在目前的VS 2019 preview中还没法体验。估计后续会慢慢放开的,到时候我再写相关文章介绍它们。
相关文章:
https://blogs.msdn.microsoft.com/dotnet/2018/12/05/take-c-8-0-for-a-spin/