zoukankan      html  css  js  c++  java
  • C# 9.0 新特性预览

    C# 9.0 新特性预览 - 顶级语句

    前言

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

    目录

    [C# 9.0 新特性预览 - 类型推导的 new]
    [C# 9.0 新特性预览 - 空参数校验]
    [C# 9.0 新特性预览 - 顶级语句]
    [C# 9.0 新特性预览 - Record 类型]
    [C# 9.0 新特性预览 - 模式匹配的改善]
    [C# 9.0 新特性预览 - 源代码生成器]
    [C# 9.0 新特性预览 - 其他小的变化]

    顶级语句 (Top-level statements)

    顶级语句这个名字看起来不是那么直观,或许它的曾用名更好一些:Simple Programs,简单程序。

    目的

    想必大家都知道,即使是最简单的 C# 程序,也会有一定量的繁文缛节,因为最少也需要一个 Main 方法。这似乎妨碍了语言的学习和程序的清晰度。因此,这个特性的最主要目的就是为了初学者和代码的清晰度,让书写 C# 程序可以变得更轻松。

    语法

    语法 Spec 如下,允许在命名空间的声明前面,添加一组语句,且只允许有一个编译单元(可以认为是一个源文件)拥有这种语句:

    compilation_unit
        : extern_alias_directive* using_directive* global_attributes? statement* namespace_member_declaration*
        ;
    

    Spec 比较难懂,我们直接来看示例:简单来说,就是允许在源文件中直接书写代码语句而不用写 Main 方法:

    System.Console.WriteLine("Hi!");
    

    以上代码会被翻译为:

    static class $Program
    {
        static void $Main(string[] args)
        {
            System.Console.WriteLine("Hi!");
        }
    }
    

    可以看到,WriteLine语句被自动的包在了一个类和 Main 方法里面。
    自动生成的 Main 方法的返回值也会根据是否异步以及是否有返回值来变化,例如:

    await System.Threading.Tasks.Task.Delay(1000);
    System.Console.WriteLine("Hi!");
    return 0;
    

    会被翻译为:

    static class $Program
    {
        static async Task<int> $Main(string[] args)
        {
            await System.Threading.Tasks.Task.Delay(1000);
            System.Console.WriteLine("Hi!");
            return 0;
        }
    }
    

    各种场景

    • 支持在 using 语句后面:
    using System;
    
    Console.Write("Hi!");
    

    会被翻译为:

    using System;
    
    static class $Program
    {
        static void $Main(string[] args)
        {
            Console.Write("Hi!");
        }
    }
    
    • 也可以加上本地函数:
    local();
    void local() => System.Console.WriteLine(2);
    
    • 可以与其它代码共存,例如类的声明:
    Type.M();
    static class Type
    {
        public static void M()
        {
            System.Console.WriteLine("Hi!");
        }
    }
    

    稍微复杂一点的:

    await using (var x = new C())
    {
        System.Console.Write("body ");
    }
    class C : System.IAsyncDisposable, System.IDisposable
    {
        public System.Threading.Tasks.ValueTask DisposeAsync()
        {
            System.Console.Write("DisposeAsync");
            return new System.Threading.Tasks.ValueTask(System.Threading.Tasks.Task.CompletedTask);
        }
        public void Dispose()
        {
            System.Console.Write("IGNORED");
        }
    }
    
    • 同时兼容了using alias的语法
    using alias1 = Test;
    string Test() => ""1"";
    System.Console.WriteLine(Test());
    class Test {}
    delegate Test D(alias1 x);
    namespace N1
    {
        using alias2 = Test;
        delegate Test D(alias2 x);
    }
    
    • 也可以同时与显示的 Main 方法声明在一起,只不过显示的Main方法会被忽略掉并提示一个警告
    using System;
    using System.Threading.Tasks;
    System.Console.Write("Hi!");
    class Program
    {
        static void Main() // warning CS7022: The entry point of the program is global code; ignoring 'Program.Main()' entry point
        {
            Console.Write("hello");
        }
    }
    

    限制

    • 不支持在多个编译单元下拥有顶级语句:
    // file1.cs
    System.Console.WriteLine("1"); // error CS9001: Only one compilation unit can have top-level statements.
    
    // file2.cs
    System.Console.WriteLine("2"); // error CS9001: Only one compilation unit can have top-level statements.
    
    • 不能放在类的内部
    class Test
    {
        System.Console.WriteLine("Hi!"); // ERROR
    }
    
    • 不能放在命名空间的内部
    namespace Test
    {
        System.Console.WriteLine("Hi!"); // ERROR
    }
    
    • 要么所有分支都有返回值,要么都没有
    System.Console.WriteLine();
    if (args.Length == 0)
    {
        return 10; // error CS0161: 不是所有代码分支都有返回值
    }
    
    • 虽然可以可以与类声明一起写,但是在类中是无法调用到 Main 方法 args 入参的,因为编译时会编译为两个类
    System.Console.WriteLine(args);
    class Test
    {
        void M()
        {
            System.Console.WriteLine(args); // ERROR
        }
    }
    
    • 自然,你也不能用 args 来命名本地函数
    args(1);
    void args(int x) // ERROR
    {}
    

    参考

    [Proposal: Simplified Null Argument Checking]
    [Unit test: NullCheckedParameterTests.cs]
    [LDM-2019-07-10.md]

  • 相关阅读:
    sizeof与strlen的区别
    面试题46:求1+2+...+n
    opennebula 安装指定参数
    opennebula 开发记录
    virsh 查看hypervisor特性
    opennebula kvm日志
    Cgroup
    opennebula kvm 创建VM oned报错日志
    opennebula kvm 创建虚拟机错误
    golang hello
  • 原文地址:https://www.cnblogs.com/Rwing/p/csharp-9-0-preview-top-level-statements.html
Copyright © 2011-2022 走看看