许秀娥 發表於 2020-9-23 08:41:00

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

<h1 id="c-90-新特性预览---顶级语句">C# 9.0 新特性预览 - 顶级语句</h1>
<p></p>
<h3 id="前言">前言</h3>
<p>随着 .NET 5 发布日期的日益临近,其对应的 C# 新版本已确定为 C# 9.0,其中新增加的特性(或语法糖)也已基本锁定,本系列文章将向大家展示它们。<br><br>
</p>
<h3 id="目录">目录</h3>
<p><br><br><br><br><br><br><br></p>
<p></p>
<h3 id="顶级语句-top-level-statements">顶级语句 (Top-level statements)</h3>
<p>顶级语句这个名字看起来不是那么直观,或许它的曾用名更好一些:Simple Programs,简单程序。<br>
</p>
<h4 id="目的">目的</h4>
<p>想必大家都知道,即使是最简单的 C# 程序,也会有一定量的繁文缛节,因为最少也需要一个 Main 方法。这似乎妨碍了语言的学习和程序的清晰度。因此,这个特性的最主要目的就是为了初学者和代码的清晰度,让书写 C# 程序可以变得更轻松。<br>
</p>
<h4 id="语法">语法</h4>
<p>语法 Spec 如下,允许在命名空间的声明前面,添加一组语句,且只允许有一个编译单元(可以认为是一个源文件)拥有这种语句:</p>
<pre><code class="language-csharp">compilation_unit
    : extern_alias_directive* using_directive* global_attributes? statement* namespace_member_declaration*
    ;
</code></pre>
<p>Spec 比较难懂,我们直接来看示例:简单来说,就是允许在源文件中直接书写代码语句而不用写 Main 方法:</p>
<pre><code class="language-csharp">System.Console.WriteLine("Hi!");
</code></pre>
<p>以上代码会被翻译为:</p>
<pre><code class="language-csharp">static class $Program
{
    static void $Main(string[] args)
    {
      System.Console.WriteLine("Hi!");
    }
}
</code></pre>
<p>可以看到,WriteLine语句被自动的包在了一个类和 Main 方法里面。<br>自动生成的 Main 方法的返回值也会根据是否异步以及是否有返回值来变化,例如:</p>
<pre><code class="language-csharp">await System.Threading.Tasks.Task.Delay(1000);
System.Console.WriteLine("Hi!");
return 0;
</code></pre>
<p>会被翻译为:</p>
<pre><code class="language-csharp">static class $Program
{
    static async Task&lt;int&gt; $Main(string[] args)
    {
      await System.Threading.Tasks.Task.Delay(1000);
      System.Console.WriteLine("Hi!");
      return 0;
    }
}
</code></pre>
<p></p>
<h4 id="各种场景">各种场景</h4>
<ul>
<li>支持在 using 语句后面:</li>
</ul>
<pre><code class="language-csharp">using System;

Console.Write("Hi!");
</code></pre>
<p>会被翻译为:</p>
<pre><code class="language-csharp">using System;

static class $Program
{
    static void $Main(string[] args)
    {
      Console.Write("Hi!");
    }
}
</code></pre>
<ul>
<li>也可以加上本地函数:</li>
</ul>
<pre><code class="language-csharp">local();
void local() =&gt; System.Console.WriteLine(2);
</code></pre>
<ul>
<li>可以与其它代码共存,例如类的声明:</li>
</ul>
<pre><code class="language-csharp">Type.M();
static class Type
{
    public static void M()
    {
      System.Console.WriteLine("Hi!");
    }
}
</code></pre>
<p>稍微复杂一点的:</p>
<pre><code class="language-csharp">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");
    }
}
</code></pre>
<ul>
<li>同时兼容了using alias的语法</li>
</ul>
<pre><code class="language-csharp">using alias1 = Test;
string Test() =&gt; ""1"";
System.Console.WriteLine(Test());
class Test {}
delegate Test D(alias1 x);
namespace N1
{
    using alias2 = Test;
    delegate Test D(alias2 x);
}
</code></pre>
<ul>
<li>也可以同时与显示的 Main 方法声明在一起,只不过显示的Main方法会被忽略掉并提示一个警告</li>
</ul>
<pre><code class="language-csharp">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");
    }
}
</code></pre>
<p></p>
<h4 id="限制">限制</h4>
<ul>
<li>不支持在多个编译单元下拥有顶级语句:</li>
</ul>
<pre><code class="language-csharp">// 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.
</code></pre>
<ul>
<li>不能放在类的内部</li>
</ul>
<pre><code class="language-csharp">class Test
{
    System.Console.WriteLine("Hi!"); // ERROR
}
</code></pre>
<ul>
<li>不能放在命名空间的内部</li>
</ul>
<pre><code class="language-csharp">namespace Test
{
    System.Console.WriteLine("Hi!"); // ERROR
}
</code></pre>
<ul>
<li>要么所有分支都有返回值,要么都没有</li>
</ul>
<pre><code class="language-csharp">System.Console.WriteLine();
if (args.Length == 0)
{
    return 10; // error CS0161: 不是所有代码分支都有返回值
}
</code></pre>
<ul>
<li>虽然可以可以与类声明一起写,但是在类中是无法调用到 Main 方法 args 入参的,因为编译时会编译为两个类</li>
</ul>
<pre><code class="language-csharp">System.Console.WriteLine(args);
class Test
{
    void M()
    {
      System.Console.WriteLine(args); // ERROR
    }
}
</code></pre>
<ul>
<li>自然,你也不能用 args 来命名本地函数</li>
</ul>
<pre><code class="language-csharp">args(1);
void args(int x) // ERROR
{}
</code></pre>
<p></p>
<h3 id="参考">参考</h3>
<p><br><br></p><br><br>
来源:https://www.cnblogs.com/Rwing/p/csharp-9-0-preview-top-level-statements.html
頁: [1]
查看完整版本: C# 9.0 新特性预览 - 顶级语句