1. 程式人生 > >C# 9 新特性 —— 補充篇

C# 9 新特性 —— 補充篇

# 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