歷史回顧 - C# 10 新功能盤點
| | | 0 | |
參考資料:微軟官方文件 C# 10
C# 10 發佈於 2021 年 11 月,跟 .NET 6 一起推出。新功能如下:
- 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 - struct 改進
C# 10 對 struct 做了諸多改良,包括無參數建構/初始化情境、with 表達式... 等。 - Interpolated string handlers
程式可客製插值字串處理常式(Interpolated String Handler)讓框架/自訂類型攔截 $"......" 決定處理方式,省下不必要的拼接提升效能,最經典應用是 Logging 時依據 LogLevel 決定要不要省略非必要處理,例如:實作方式說明// 假設有支援 interpolated string handler 的 Logger.Log // 若 Debug 未啟用,expensiveComputation() 不會執行 Logger.Log(LogLevel.Debug, $"User {userId} did {expensiveComputation()}"); - global using 指示詞
在 GlobalUsings.cs 可宣告全專案通用的 using,減少在每個檔案重複宣告。
或在 .csproj:global using System; global using System.Collections.Generic; global using System.Linq;<ItemGroup> <Using Include="System" /> <Using Include="System.Collections.Generic" /> </ItemGroup> - File-Scoped Namespace
檔案開頭宣告命名空間,可省下巢狀大括號及一個層級縮排,並提高可讀性:namespace MyApp.Models; public class User { public string Name { get; set; } = ""; } - 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" }) { ... } - Lambda 的自然型別 (Natural Type)
編譯器可由上下文自動推斷 Lambda 的委派型別,讓宣告更短更有彈性。var adder = (int x, int y) => x + y; // 編譯器推斷為 Func<int,int,int> int sum = adder(2, 3); - 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; // 類似地明確回傳型別 - Lambda 可套用 Attribute
Lambda 本身或其參數可套用 Attribute,例如 DebuggerStepThrough、特定分析或調用約束條件等場景,讓 Lambda 與一般方法更一致,利於診斷與工具鏈整合。var f = [SomeAttribute] (int x) => x * x; // 或針對參數 var g = ([NotNull] string s) => s.Length; - 常值插值字串 (Const Interpolated Strings)
C# 10 允許 const 字串使用插值,只要插值項本身也都是常值。const string Name = "Alan"; const string Title = $"{Name} - Employee"; // 合法,因為 Name 是常值 - 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) - 更精準的 definite assignment 與 null 狀態分析警告
編譯器在變數的賦值保證以及可空值分析上更嚴謹,減少誤報或漏報,提升 Null 相關問題的偵測品質。 在複雜流程或模式比對情境下,分析更貼近實際執行路徑,能更早發現可能的未賦值或 null 使用風險。 - 同時允許在解構中進行宣告與指定
解構 (Deconstruction) 現在可同時包含宣告與指派,增強撰寫靈活性與可讀性。int a; (a, var b) = (1, "x"); // 指派 a,同時宣告 b 並解構 (int c, _) = (a + 1, b); // 部分忽略,並從已有變數計算 - 方法可使用 AsyncMethodBuilder 屬性
允許在方法層級套用 AsyncMethodBuilder 屬性,控制非同步方法使用的 builder 型別,有助於微調效能或行為。using System.Runtime.CompilerServices; public class CustomTaskMethodBuilder { /* ... 自訂 builder ... */ } public class Demo { [AsyncMethodBuilder(typeof(CustomTaskMethodBuilder))] public async Task<int> WorkAsync() => 42; } - 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" - #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