原文:《C# Version 3.0 Specification》,Microsoft
翻譯:lover_P
一個對象創建表達式可以包含一個對象或集合初始化器,用於初始化新創建的對象的成員或新創建的集合的元素。
object-creation-expression:
new type ( argument-listopt ) object-or-collection-initializeropt
new type object-or-collection-initializer
object-or-collection-initializer:
object-initializer
collection-initializer
一個對象創建表達式可以省略構造器參數列表,並將其連同圓括號一起替換為一個對象或集合初始化器。省略構造器參數列表並將其連同圓括號一起替換為一個對象或集合初始化器等價於指定一個空的參數列表。
在執行一個帶有對象或集合初始化器的對象創建表達式時,首先調用實例構造器,然後執行對象或集合初始化器指定的成員或元素初始化。
對象或集合初始化器不能引用正在初始化的對象實例。
4.1 對象初始化器
對象初始化器指定了對象的一個或多個域或屬性的值。
object-initializer:
{ member-initializer-listopt }
{ member-initializer-list , }
member-initializer-list:
member-initializer
member-initializer-list , member-initializer
member-initializer:
identifIEr = initializer-value
initializer-value:
expression
object-or-collection-initializer
對象初始化器由一系列的成員初始化器構成,包圍在{和}記號中,並用逗號進行分隔。每個成員初始化器以對象的一個可訪問的域或屬性的名字開始,後跟一個等號,之後是一個表達式或一個對象或集合初始化器。如果對象初始化其中包括了對同一個域或屬性的多於一個的成員初始化器,將會發生錯誤。
在等號後面指定了表達式的成員初始化器的處理與域和屬性的賦值一致。
在等號後面指定了對象初始化器的成員初始化器也是對一個嵌套對象的初始化。與為域或屬性賦一個新值不同,對象初始化器中的賦值被視為對域或屬性的成員進行賦值。一個具有值類型的屬性不能通過這種構造來進行初始化。
在等號後面指定了集合初始化器的成員初始化器也是對一個嵌套集合的初始化。與為域或屬性賦一個新的集合不同,初始化器中給定的元素將被添加到域或屬性所引用的集合中。該域或屬性必須是一個滿足下一節所指定的需求的集合類型。
下面的類表是一個具有兩個坐標值的點:
public class Point
{
int x, y;
public int X { get { return x; } set { x = value; } }
public int Y { get { return y; } set { y = value; } }
}
Point的一個實例可以像下面這樣創建和初始化:
var a = new Point { X = 0, Y = 1 };
其等價於:
var a = new Point();
a.X = 0;
a.Y = 1;
下面的類表是一個具有兩個點的矩形:
public class Rectangle
{
Point p1, p2;
public Point P1 { get { return p1; } set { p1 = value; } }
public Point P2 { get { return p2; } set { p2 = value; } }
}
可以像下面這樣創建和初始化一個Rectangle:
var r = new Rectangle {
P1 = new Point { X = 0, Y = 1 },
P2 = new Point { X = 2, Y = 3 }
};
其等價於:
var r = new Rectangle();
var __p1 = new Point();
__p1.X = 0;
__p1.Y = 1;
r.P1 = __p1;
var __p2 = new Point();
__p2.X = 2;
__p2.Y = 3;
r.P2 = __p2;
其中的__p1和__p2是臨時變量,在其他地方不可見也不可訪問。
如果Rectangle的構造器分配了兩個嵌套的Point實例:
public class Rectangle
{
Point p1 = new Point();
Point p2 = new Point();
public Point P1 { get { return p1; } }
public Point P2 { get { return p2; } }
}
下面的構造可以用來初始化內嵌的Point實例,而不是為其賦以新值:
var r = new Rectangle {
P1 = { X = 0, Y = 1 },
P2 = { X = 2, Y = 3 }
};
其等價於:
var r = new Rectangle();
r.P1.X = 0;
r.P1.Y = 1;
r.P2.X = 2;
r.P2.Y = 3;
4.2 集合初始化器
集合初始化器指定了集合的元素。
collection-initializer:
{ element-initializer-listopt }
{ element-initializer-list , }
element-initializer-list:
element-initializer
element-initializer-list , element-initializer
element-initializer:
non-assignment-expression
一個集合初始化器由一系列的元素初始化器構成,包圍在{和}記號之間,並使用逗號進行分隔。每個元素初始化器指定一個元素,該元素將被添加到待初始化的集合對象中。為了避免與成員初始化器混淆,元素初始化器不能是賦值表達式。
下面是包含了集合初始化器的對象創建表達式的一個例子:
List<int> digits = new List<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
可以應用集合初始化器的對象的類型必須實現了System.Collections.Generic.ICollections<T>並指定了確定的T。此外,必須存在從每個元素初始化器的類型到T的隱式轉換。如果這些條件不能滿足,就會產生一個編譯期錯誤。集合初始化器將依次對每個指定的元素調用ICollection<T>.Add(T)。
下面的類表是一個具有一個名字和一組電話號碼的通訊錄:
public class Contact
{
string name;
List<string> phoneNumbers = new List<string>();
public string Name { get { return name; } set { name = value; } }
public List<string> PhoneNumbers { get { return phoneNumbers; } }
}
可以像下面這樣創建和初始化一個List<Contact>:
var contacts = new List<Contact> {
new Contact {
Name = "Chris Smith",
PhoneNumbers = { "206-555-0101", "425-882-8080" }
},
new Contact {
Name = "Bob Harris",
PhoneNumbers = { "650-555-0199" }
}
};
其等價於:
var contacts = new List<Contact>();
var __c1 = new Contact();
__c1.Name = "Chris Smith";
__c1.PhoneNumbers.Add("206-555-0101");
__c1.PhoneNumbers.Add("425-882-8080");
contacts.Add(__c1);
var __c2 = new Contact();
__c2.Name = "Bob Harris";
__c2.PhoneNumbers.Add("650-555-0199");
contacts.Add(__c2);
其中__c1和__c2是臨時變量,在其他地方不可見且不可訪問。