這是一個集合初始化器的一個特例。
在C#中,數組初始化符花括號已被推廣到與任何集合類構造函數一起工作。
任何類支持這些如果它實現System.Collections.IEnumerable
並且有一個或多個Add()
方法。 Eric Lippert has a good post about this type of "pattern matching" in C#:編譯器在這裏做的是他們稱之爲「duck typing」的東西,而不是傳統的強類型OOP,其中類的功能基於繼承和接口實現進行識別。 C#在幾個地方執行此操作。那篇我不知道的文章裏有很多東西。
public class Foo : List<String>
{
public void Add(int n)
{
base.Add(n.ToString());
}
public void Add(DateTime dt, double x)
{
base.Add($"{dt.ToShortDateString()} {x}");
}
}
然後這個編譯:
var f = new Foo { 0, 1, 2, "Zanzibar", { DateTime.Now, 3.7 } };
這句法糖爲此:
var f = new Foo();
f.Add(0);
f.Add(1);
f.Add(2)
f.Add("Zanzibar");
f.Add(DateTime.Now, 3.7);
你可以玩這些一些很奇怪的比賽。我不知道全力以赴是否是個好主意(其實我做知道 - 事實並非如此),但你可以。我寫了一個命令行解析器類,您可以在其中通過集合初始值設定器定義選項。它有12個過載的Add
,帶有不同的參數列表,其中很多都是通用的。編譯器可以推斷的任何東西都是公平的遊戲。
再一次,您可以將這種超越遞減的功能推向功能濫用的地步。
你看到的是相同的初始化語法,它可以讓你的這個類本身就已經創造了一個不可轉讓的成員做集合初始化的擴展:
public class Bar
{
public Foo Foo { get; } = new Foo();
}
現在.. 。
var b = new Bar { Foo = { 0, "Beringia" } };
{ 0, "Beringia" }
對於Foo
實例Bar
爲自己創造了一個集合初始化;它的語法糖這樣的:
var b = new Bar();
b.Foo.Add(0);
b.Foo.Add("Beringia");
編譯器的解決語法糖初始化使用的Foo.Add()
重載意願是有道理的,當你看它的方式。我認爲能夠做到這一點很棒,但我對他們選擇的語法並不滿意。如果你發現賦值運算符是一個紅鯡魚,其他人也會。
但我不是語法仲裁者,這可能是最好的所有有關。
最後,這還與對象初始化:
public class Baz
{
public String Name { get; set; }
}
public class Bar
{
public Foo Foo { get; } = new Foo { 1000 };
public Baz Baz { get; } = new Baz { Name = "Initial name" };
}
所以......
var b = new Bar { Foo = { 0, "Beringia" }, Baz = { Name = "Arbitrary" } };
裏面居然變成...
var b = new Bar();
b.Foo.Add(0);
b.Foo.Add("Beringia");
b.Baz.Name = "Arbitrary";
我們不能初始化Bar.Baz
,因爲它沒有setter,但我們可以初始化它的屬性,就像我們可以初始化它的屬性一樣ems在Foo
。即使它們已經被連接到實際構造函數的不同對象初始化器初始化,情況也是如此。
正如您所期望的,收集初始值設定項是累積值:Bar.Foo
將包含三項:{ "1000", "0", "Beringia" }
。
當您將花括號視爲一列賦值語句或Add()
過載調用的縮寫時,它將全部對焦。
但我同意,在左值沒有被分配到的情況下,等號是震耳欲聾的。
獎金
這裏的另一種模式匹配功能,我學到了from that Eric Lippert article:
public static class HoldMyBeerAndWatchThis
{
public static IEnumerable<int> Select(Func<String, String> f)
{
yield return f("foo").Length;
}
}
因此...
var x = from s in HoldMyBeerAndWatchThis select s;
所有你需要的select
工作就是你的事」重新選擇必須有一個名爲Select
的方法,該方法返回那樣的庸醫像IEnumerable
@ @ EricLippert關於foreach
的評論在the linked article(感謝Eric!)中列出,並且需要Func<T,T>
參數。
我剛剛在前幾天發現了這一點,我還沒有能夠確切地分離它是如何工作的。 – DLeh
根據[初始化程序中的MSDN文檔](https://msdn.microsoft.com/en-us/library/bb384062.aspx),似乎編譯器在使用此初始化程序時會重複調用「Add」。請注意,您不能在變量聲明中直接使用此語法。例如'IList children = {「childfoo」,「childbar」}'不會編譯 –
@ stephen.vakil:有時候,你幾乎可以。 'string [] children = {「childfoo」,「childbar」};' – recursive