C# 3.0 引入的物件初始化器與集合初始化器,是語言向宣告式風格邁進的重要一步。它們不僅減少樣板程式碼,更讓物件圖的建構與 LINQ 查詢表達式緊密結合。本文系統梳理語法規則、編譯行為與進階用法。
物件建立運算式現支援兩種形式:
new Type(arguments) { memberInitializers }
new Type { memberInitializers } // 省略建構函式引數,等同 new Type() { ... }
執行語義:先呼叫實例建構函式,再依序執行成員初始化器。初始化器不能參考正在初始化的物件實例(即不可使用 this)。
public class Point
{
public int X { get; set; }
public int Y { get; set; }
public PointColor Color { get; set; }
public Point() { }
public Point(PointColor color) { Color = color; }
public Point(int x, int y) { X = x; Y = y; Color = PointColor.Green; }
}
各種初始化形式:
// 隱式類型區域變數 + 物件初始化器(呼叫預設建構函式)
var p1 = new Point { X = 100, Y = 200 };
// 顯式型別 + 物件初始化器
Point p2 = new Point { X = 100, Y = 200 };
// 顯式呼叫無參數建構函式(語意相同)
Point p3 = new Point() { X = 100, Y = 200 };
// 呼叫自訂建構函式並覆寫屬性
Point p4 = new Point(PointColor.Black) { X = 100, Y = 200 };
// 結果:X=100, Y=200, Color=Black(建構函式設定的 Color 生效,未被覆寫)
Point p5 = new Point(10, 20) { X = 100, Y = 200 };
// 結果:X=100, Y=200, Color=Green(建構函式參數 10,20 被後續屬性指派覆蓋)
成員初始化器右側可再為物件或集合初始化器,支援深層物件圖建構:
public class Rectangle
{
public Point TopLeft { get; set; } = new Point();
public Point BottomRight { get; set; } = new Point();
}
Rectangle rect = new Rectangle
{
TopLeft = new Point { X = 100, Y = 100 },
BottomRight = new Point { X = 200, Y = 200 }
};
編譯器會自動建立巢狀物件並指派給屬性,極大簡化複雜物件圖的建構程式碼。
適用於實作 System.Collections.Generic.ICollection<T> 的型別。語法:
List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
List<Point> points = new List<Point>
{
new Point { X = 10, Y = 20 },
new Point { X = 100, Y = 200 }
};
限制:
X = 1),必須為物件建立運算式或值。ICollection<T>,故 ArrayList 等非泛型集合無法使用。Add 方法呼叫。以下初始化器:
var list = new List<Point>
{
new Point { X = 10, Y = 20 },
new Point { X = 100, Y = 200 }
};
編譯器轉換為:
var <>g__initLocal0 = new List<Point>();
var <>g__initLocal1 = new Point();
<>g__initLocal1.X = 10;
<>g__initLocal1.Y = 20;
<>g__initLocal0.Add(<>g__initLocal1);
var <>g__initLocal2 = new Point();
<>g__initLocal2.X = 100;
<>g__initLocal2.Y = 200;
<>g__initLocal0.Add(<>g__initLocal2);
var list = <>g__initLocal0;
Add,若集合有容量預估,手動 new List<T>(capacity) 後再 AddRange 可能更高效。