為讓 LINQ 無縫整合 C#,微軟在 C# 3.0 新增相關特性,本文介紹前三項:var、集合初始化、匿名類型與 Lambda 表達式。
var:區域變數型別推斷,非動態類型。編譯器依初始化運算式推斷型別(內建、匿名、使用者定義、Framework 類別)。var i = 5; 編譯後等同 int i = 5;。不可用於未初始化或 null。
var i = 5; // int
var j = 23.56; // double
var k = "C Sharp"; // string
var x; // 錯誤
var y = null; // 錯誤
var z = {1,2,3}; // 錯誤
物件與集合初始化:VS2008 編譯器自動生成屬性 setter,可一行完成賦值。物件初始化器用大括號包裹成員,逗號分隔。
class User { public int ID {get;set;} public string Name {get;set;} public int Age {get;set;} }
User u = new User { ID = 1, Name = "lfm", Age = 22 };
List<User> users = new List<User> {
new User { ID = 1, Name = "lfm", Age = 22 },
new User { ID = 2, Name = "tmx", Age = 25 }
};
匿名類型:無需顯式定義類型,封裝唯讀屬性到單一物件。型別名由編譯器生成,原始碼不可存取。屬性型別由編譯器推斷。賦值給變數必須用 var。
var p1 = new { ID = 1, Name = "lfm", Age = 22 };
var p2 = new { ID = 2, Name = "tmx", Age = 25 };
p1 = p2; // 結構相同可互相賦值
編譯器視為相同結構的匿名類型共享型別資訊。匿名類型為參考型別,方法範圍內有效。跨方法邊界傳遞需轉為 object,失去強類型優勢,建議改用具名類別/結構。
Lambda 表達式(=> 運算子)提供簡潔語法表示運算規則。C# 3.0 中為匿名函數,可包含運算式與陳述式,用於建立委派或表達式樹。
演進脈絡:
delegate(bool) Filter 需額外定義方法。delegate(int i) { return (i & 1) == 1; } 解決一次性方法問題,但語法冗長。i => (i & 1) == 1 簡潔易讀。語法形式:
x => x * x(讀作 "x goes to x 乘 x")(p1, p2) => expr(p1, p2) => { stmt1; stmt2; return result; }Lambda 實為匿名委派,可用於委派適用處。左側為輸入參數,右側為輸出結果。例:x => x.Length > 0 等同 delegate(string x) { return x.Length > 0; }。
應用於過濾陣列:
int[] nums = {1,2,3,4,5,6,7,8,9,10};
int[] oddNums = Common.FilterArrayOfInts(nums, i => (i & 1) == 1);
比匿名委派可讀性大幅提升。