C# 9 新特性 —— 補充篇
阿新 • • 發佈:2021-01-07
# C# 9 新特性 —— 補充篇
## Intro
前面我們分別介紹了一些 C# 9 中的新特性,還有一些我覺得需要了解一下的新特性,寫一篇作為補充。
## Top-Level Statements
在以往的程式碼裡,一個應用程式必須要有 `Main` 方法才能執行,從 C# 9 開始,支援沒有 `Main` 方法的程式,實際編譯之後還是會有一個 `Main` 方法的,使用示例如下:
``` csharp
using static System.Console;
WriteLine("Hello World!");
```
實際編譯出來的結果如下:
![](https://img2020.cnblogs.com/blog/489462/202101/489462-20210106233638987-1722288603.png)
實際會生成一個沒有名稱空間的 `$` 的型別,類中定義的有一個名稱是 `$` 的靜態方法
## Improved discards in lambda input parameter
從 C# 7.2 開始,我們可以使用 `_` 來代表一個不使用的變數,廢棄變數,但是在 lambda 表示式裡預設不能有同名的引數名,從 C# 9 開始,支援多個引數同時使用 `_` 來表示,如下所示:
``` csharp
Func constant = (_, _) => 42;
```
## Attributes for local function
從 C# 9 開始,我們可以在區域性方法(本地方法)上設定 Attribute
``` csharp
public static void MainTest()
{
InnerTest();
[MethodImpl(MethodImplOptions.Synchronized)]
void InnerTest()
{
Console.WriteLine(nameof(InnerTest));
}
}
```
## Partition methods
在 C# 2.0 之後就支援了分部類,通常分部類會出現在動態程式碼生成的地方,對於想要將一個型別拆分到多個檔案裡,我們通常也會考慮用到分部類。
C# 3.0 開始支援了分部方法,但是功能比較弱,使用起來有一些限制:
- 分部型別各部分中的簽名必須匹配。
- 方法必須返回 void。
- 不允許使用訪問修飾符。 分部方法是隱式 `private` 的。
C# 9 增強了分部方法的支援,分部方法的使用,只能在一個地方有方法體,目前主要是為了 Source Generator 引入了這個語言特性,可以在一個地方定義方法,在另外一個地方實現方法體,示例如下:
``` csharp
partial class PartialMethod
{
public static partial void MainTest();
static partial void Test1();
}
partial class PartialMethod
{
public static partial void MainTest()
{
Test1();
Console.WriteLine("Partial method works");
}
}
```
符合 C# 3.0 分部方法規則的允許沒有方法體,否則必須要有方法體
## `ModuleInitializer`
`Source Generator` 除了上面的分部方法之外,還引入了一個 `ModuleInitializer` 的概念,就像它的名字,模組初始化器,當用到某個模組的時候就會呼叫對應的 `ModuleInitializer` 方法進行初始化操作
`ModuleInitializer` 定義如下:
``` csharp
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Method, Inherited = false)]
public sealed class ModuleInitializerAttribute : Attribute
{
}
}
```
使用示例如下:
```csharp
internal static class ModuleInitializerSample
{
///
/// Initializer for specific module
///
/// Must be static
/// Must be parameter-less
/// Must return void
/// Must not be a generic method
/// Must not be contained in a generic class
/// Must be accessible from the containing module
///
[ModuleInitializer]
public static void Initialize()
{
Console.WriteLine($"{nameof(ModuleInitializerAttribute)} works");
}
}
```
`ModuleInitlializer` 對應的方法有幾個要求
- 必須是靜態方法
- 不能有方法引數,無引數方法
- 方法沒有返回值,返回型別必須是 `void`
- 不能是泛型方法
- 不能在泛型類中
- 必須能夠被所在模組訪問的到(至少是 internal)
![](https://img2020.cnblogs.com/blog/489462/202101/489462-20210106234156030-419932456.png)
![](https://img2020.cnblogs.com/blog/489462/202101/489462-20210106234209040-1957973110.png)
來看反編譯的程式碼,可以看到有一個 `Module` 的類,在這個 `Module` 類的靜態構造方法裡會去呼叫宣告為 `ModuleInitializer` 的方法
![](https://img2020.cnblogs.com/blog/489462/202101/489462-20210106234356098-1120644185.png)
## Function Pointer
C# 9 支援方法指標,對委託進一步的”C++化“,進一步提升效能,屬於非安全程式碼,使用需開啟 `unsafe`,使用示例如下:
``` csharp
public static unsafe void MainTest()
{
delegate* pointer = &Test;
var result = pointer(1, 1);
Console.WriteLine(result);
}
private static int Test(int num1, int num2)
{
Console.WriteLine($"Invoke in {nameof(Test)}, {num1}_{num2}");
return num1 + num2;
}
```
## Static Anoymouse Method
C# 9 開始支援在匿名方法或者表示式前宣告 `static`,宣告 `static` 之後就不能使用例項變數,只能使用靜態變數,如下所示:
``` csharp
internal class StaticAnonymousMethod
{
private readonly int num = 1;
public void MainTest()
{
// anonymous method
Action action = () => { Console.WriteLine(num); };
Action action1 = static () => { };// can not access `num`
//expression
Expression> expression = i => i > num;
Expression> expression1 = static i => i > 1;// can not access `num`
}
}
```
## Covariant Return Type
C# 9 開始支援返回型別的 `Covariant`(協變), 對於 `override` 方法可返回從重寫基方法的返回型別派生的型別。 這對於`record`和其他支援工廠方法的型別會很有用。可以參考下面的使用示例:
``` csharp
internal class CovariantReturnType
{
private abstract class Operation
{
}
private abstract class OperationFactory
{
public abstract Operation GetOperation();
}
private class AddOperation : Operation
{
}
private class AddOperationFactory : OperationFactory
{
// 返回型別協變,返回具體的型別而不是抽象類中宣告的型別
public override AddOperation GetOperation()
{
return new();
}
}
public static void MainTest()
{
var factory = new AddOperationFactory();
factory.GetOperation();
}
}
```
## More
除此之外還有一些小的更新特性,詳細可以參考文末給出的官方文件。
## Reference
- https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-9
- https://github.com/WeihanLi/SamplesInPractice/tree/master/CSharp9Sample