C# 9.0 新特性預覽 - 頂級語句
阿新 • • 發佈:2020-09-23
# C# 9.0 新特性預覽 - 頂級語句
### 前言
隨著 .NET 5 釋出日期的日益臨近,其對應的 C# 新版本已確定為 C# 9.0,其中新增加的特性(或語法糖)也已基本鎖定,本系列文章將向大家展示它們。
### 目錄 [[C# 9.0 新特性預覽 - 型別推導的 new](https://www.cnblogs.com/Rwing/p/csharp-9-0-preview-target-typed-new.html)]
[[C# 9.0 新特性預覽 - 空引數校驗](https://www.cnblogs.com/Rwing/p/csharp-9-0-preview-null-arg-checking.html)]
[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 如下,允許在名稱空間的宣告前面,新增一組語句,且只允許有一個編譯單元(可以認為是一個原始檔)擁有這種語句:
```csharp
compilation_unit
: extern_alias_directive* using_directive* global_attributes? statement* namespace_member_declaration*
;
```
Spec 比較難懂,我們直接來看示例:簡單來說,就是允許在原始檔中直接書寫程式碼語句而不用寫 Main 方法:
```csharp
System.Console.WriteLine("Hi!");
```
以上程式碼會被翻譯為:
```csharp
static class $Program
{
static void $Main(string[] args)
{
System.Console.WriteLine("Hi!");
}
}
```
可以看到,WriteLine語句被自動的包在了一個類和 Main 方法裡面。
自動生成的 Main 方法的返回值也會根據是否非同步以及是否有返回值來變化,例如:
```csharp
await System.Threading.Tasks.Task.Delay(1000);
System.Console.WriteLine("Hi!");
return 0;
```
會被翻譯為:
```csharp
static class $Program
{
static async Task $Main(string[] args)
{
await System.Threading.Tasks.Task.Delay(1000);
System.Console.WriteLine("Hi!");
return 0;
}
}
```
#### 各種場景
- 支援在 using 語句後面:
```csharp
using System;
Console.Write("Hi!");
```
會被翻譯為:
```csharp
using System;
static class $Program
{
static void $Main(string[] args)
{
Console.Write("Hi!");
}
}
```
- 也可以加上本地函式:
```csharp
local();
void local() => System.Console.WriteLine(2);
```
- 可以與其它程式碼共存,例如類的宣告:
```csharp
Type.M();
static class Type
{
public static void M()
{
System.Console.WriteLine("Hi!");
}
}
```
稍微複雜一點的:
```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");
}
}
```
- 同時相容了using alias的語法
```csharp
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方法會被忽略掉並提示一個警告
```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");
}
}
```
#### 限制
- 不支援在多個編譯單元下擁有頂級語句:
```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.
```
- 不能放在類的內部
```csharp
class Test
{
System.Console.WriteLine("Hi!"); // ERROR
}
```
- 不能放在名稱空間的內部
```csharp
namespace Test
{
System.Console.WriteLine("Hi!"); // ERROR
}
```
- 要麼所有分支都有返回值,要麼都沒有
```csharp
System.Console.WriteLine();
if (args.Length == 0)
{
return 10; // error CS0161: 不是所有程式碼分支都有返回值
}
```
- 雖然可以可以與類宣告一起寫,但是在類中是無法呼叫到 Main 方法 args 入參的,因為編譯時會編譯為兩個類
```csharp
System.Console.WriteLine(args);
class Test
{
void M()
{
System.Console.WriteLine(args); // ERROR
}
}
```
- 自然,你也不能用 args 來命名本地函式
```csharp
args(1);
void args(int x) // ERROR
{}
```
### 參考
[[Proposal: Simplified Null Argument Checking](https://github.com/dotnet/csharplang/blob/master/proposals/null-arg-checking.md)]
[[Unit test: NullCheckedParameterTests.cs](https://github.com/dotnet/roslyn/blob/features%2Fparam-nullchecking/src/Compilers/CSharp/Test/Semantic/Semantics/NullCheckedParameterTests.cs)]
[[LDM-2019-07-10.md](https://github.com/dotnet/csharplang/blob/master/meetings/2019/LDM-2019-07-10.md#param)]
### 目錄 [[C# 9.0 新特性預覽 - 型別推導的 new](https://www.cnblogs.com/Rwing/p/csharp-9-0-preview-target-typed-new.html)]
[[C# 9.0 新特性預覽 - 空引數校驗](https://www.cnblogs.com/Rwing/p/csharp-9-0-preview-null-arg-checking.html)]
[C# 9.0 新特性預覽 - 頂級語句]
[C# 9.0 新特性預覽 - Record 型別]
[C# 9.0 新特性預覽 - 模式匹配的改善]
[C# 9.0 新特性預覽 - 原始碼生成器]
[C# 9.0 新特性預覽 - 其他小的變化]
[[LDM-2019-07-10.md](https://github.com/dotnet/csharplang/blob/master/meetings/2019/LDM-2019-07-10.md#param)]