參考資料:微軟官方文件 C# 10

C# 10 發佈於 2021 年 11 月,跟 .NET 6 一起推出。新功能如下:

  1. record struct
    C# 9 加入的 record 類別底層為 class,C# 10 再加入以 struct 實作的 record struct,record 特性相同但具備 struct Value Type 特性。
    public record struct Point(int X, int Y);
    
    // 可指定唯讀
    public readonly record struct Size(int Width, int Height);
    
    // 一般使用
    var p1 = new Point(3, 4);
    var p2 = new Point(3, 4);
    Console.WriteLine(p1 == p2); // True
    
  2. struct 改進
    C# 10 對 struct 做了諸多改良,包括無參數建構/初始化情境、with 表達式... 等。
  3. Interpolated string handlers
    程式可客製插值字串處理常式(Interpolated String Handler)讓框架/自訂類型攔截 $"......" 決定處理方式,省下不必要的拼接提升效能,最經典應用是 Logging 時依據 LogLevel 決定要不要省略非必要處理,例如:實作方式說明
    // 假設有支援 interpolated string handler 的 Logger.Log
    // 若 Debug 未啟用,expensiveComputation() 不會執行
    Logger.Log(LogLevel.Debug, $"User {userId} did {expensiveComputation()}");
    
  4. global using 指示詞
    在 GlobalUsings.cs 可宣告全專案通用的 using,減少在每個檔案重複宣告。
    global using System;
    global using System.Collections.Generic;
    global using System.Linq;
    
    或在 .csproj:
    <ItemGroup>
      <Using Include="System" />
      <Using Include="System.Collections.Generic" />
    </ItemGroup>
    
  5. File-Scoped Namespace
    檔案開頭宣告命名空間,可省下巢狀大括號及一個層級縮排,並提高可讀性:
    namespace MyApp.Models;
    
    public class User
    {
        public string Name { get; set; } = "";
    }
    
  6. Extended Property Patterns
    屬性模式可延伸到更深層級的巢狀屬性,讓 pattern matching 更精簡。C# 10 前後對照範例:
    // C# 10 前:需要多層嵌套
    if (person is { Address: { City: { Name: "Taipei" } } }) { ... }
    
    // C# 10:延伸屬性模式更精簡
    if (person is { Address.City.Name: "Taipei" }) { ... }
    
  7. Lambda 的自然型別 (Natural Type)
    編譯器可由上下文自動推斷 Lambda 的委派型別,讓宣告更短更有彈性。
    var adder = (int x, int y) => x + y; // 編譯器推斷為 Func<int,int,int>
    int sum = adder(2, 3);
    
  8. Lambda 可明確宣告傳回型別
    當無法自動推斷時,允許在 Lambda 標註回傳型別。
    var choose = (bool b) => b ? 1 : "two"; // ERROR: 無法推斷返回型別
    var choose = object (bool b) => b ? 1 : "two"; // 宣告返回型別為 object,推斷為 Func<bool, object>
    var chooser = bool cond => cond ? (int)1 : (int)0; // 類似地明確回傳型別
    
  9. Lambda 可套用 Attribute
    Lambda 本身或其參數可套用 Attribute,例如 DebuggerStepThrough、特定分析或調用約束條件等場景,讓 Lambda 與一般方法更一致,利於診斷與工具鏈整合。
    var f = [SomeAttribute] (int x) => x * x;
    // 或針對參數
    var g = ([NotNull] string s) => s.Length;
    
  10. 常值插值字串 (Const Interpolated Strings)
    C# 10 允許 const 字串使用插值,只要插值項本身也都是常值。
    const string Name = "Alan";
    const string Title = $"{Name} - Employee"; // 合法,因為 Name 是常值
    
  11. record 型別覆寫 ToString 可加上 sealed
    在 C# 10,覆寫 record 的 ToString 時,允許使用 sealed 修飾,防止衍生型別覆寫該方法。
    public record Person(string Name)
    {
        public sealed override string ToString() => $"Person: {Name}";
    }
    // 若嘗試再覆寫 ToString,將產生編譯錯誤 (因為父類已 sealed)
    public record Employee(string Name, string Title) : Person(Name)
    
  12. 更精準的 definite assignment 與 null 狀態分析警告
    編譯器在變數的賦值保證以及可空值分析上更嚴謹,減少誤報或漏報,提升 Null 相關問題的偵測品質。 在複雜流程或模式比對情境下,分析更貼近實際執行路徑,能更早發現可能的未賦值或 null 使用風險。
  13. 同時允許在解構中進行宣告與指定
    解構 (Deconstruction) 現在可同時包含宣告與指派,增強撰寫靈活性與可讀性。
    int a;
    (a, var b) = (1, "x");   // 指派 a,同時宣告 b 並解構
    (int c, _) = (a + 1, b);     // 部分忽略,並從已有變數計算
    
  14. 方法可使用 AsyncMethodBuilder 屬性
    允許在方法層級套用 AsyncMethodBuilder 屬性,控制非同步方法使用的 builder 型別,有助於微調效能或行為。
    using System.Runtime.CompilerServices;
    
    public class CustomTaskMethodBuilder { /* ... 自訂 builder ... */ }
    
    public class Demo
    {
        [AsyncMethodBuilder(typeof(CustomTaskMethodBuilder))]
        public async Task<int> WorkAsync() => 42;
    }
    
  15. CallerArgumentExpression 屬性
    新增 CallerArgumentExpression,可在被呼叫的方法中取得呼叫端所傳入參數「原始表達式」的字串,利於驗證與診斷訊息。例如簡化參數驗證與錯誤訊息:
    using System;
    using System.Runtime.CompilerServices;
    
    static void VerifyNotNull<T>(
        T value,
        [CallerArgumentExpression("value")] string expr = null)
    {
        if (value is null)
            throw new ArgumentNullException(expr);
    }
    
    string name = null;
    VerifyNotNull(name);  // 例外訊息的參數名會是 "name"
    
  16. #line 指示詞格式
    強化 #line 指示詞語法,可加上 (起始行, 起始字元)-(結束行, 結束字元) 與可選的字元位移,以改善像 Razor 這類產生器/DSL 的對映與偵錯體驗。
    有以下語法可利用:
    • 4 個數字: (startLine, startChar)-(endLine, endChar)
    • 5 個數字: (startLine, startChar)-(endLine, endChar) offset
    • 若未提供 offset,預設為 0,代表 UTF-16 字元位移。
    #line (10,5)-(12,20) "Generated.cs"
    // 編譯器將後續碼位移/對映到指定來源區段
    Console.WriteLine("Mapped region");
    #line default
    

A concise overview of C# 10’s key features.


Comments

Be the first to post a comment

Post a comment