• [翻译] C# 8.0 新特性


    原文: 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#

  • 相关阅读:
    SRM 588 D2 L3:GameInDarknessDiv2,DFS
    [置顶] ProDinner体验
    [置顶] 强制访问控制内核模块Smack
    Java小项目--坦克大战(version1.0)
    utf-8-validation
    is-subsequence
    perfect-rectangle
    find-the-difference
    longest-absolute-file-path
    first-unique-character-in-a-string
  • 原文地址:https://www.cnblogs.com/Rwing/p/building-c-8-0.html
Copyright © 2020-2023  润新知