2012-02-24 31 views
20

伊夫剛剛看到的一段代碼,使用一個通用的列表類實例化本身以下列方式:這是什麼語法使用新的後面的大括號內的列表?

var foo = new List<string>(){"hello", "goodbye"}; 

的構造器後的大括號是特別令人困惑。這讓我想起有點的

var bar = new string[]{"hi","bye"}; 

但在過去,我wouldve一直使用:

var foo = new List<string>(new []{"hello", "goodbye"}); 

有沒有人有一個鏈接解釋的第一行代碼的語法?我甚至不知道從哪裏開始用Google搜索它。

+36

事實上,「混淆」的語法立即提醒你*數組*的相同特徵可能表明它根本就沒有讓人迷惑,不是嗎?我們非常小心地選擇了這種語法,以便它能夠讓你確切地具有你所擁有的直覺。 – 2012-02-24 18:59:09

+0

@maxp「過去」中,您通過調用一個構造函數初始化List ,該構造函數採用IEnumerable 並使用數組初始值設定器語法創建匿名集合,並創建對同一集合的兩個引用。 TBH我不知道爲什麼編譯器不會優化第1行到第3行的語法 - 它肯定知道由'new []'生成的對象被傳入列表構造函數不能被引用以任何其他方式獨立,因此沒有必要保持活力。 – 2012-02-24 19:01:50

+7

@ValAkkapeddi:*編譯器團隊*應該如何知道編寫'List '的人將要處理那個對象?編譯器沒有特別的知識,任何特定的'List '構造函數對傳遞給它的數組都沒有特別的作用。 – 2012-02-24 19:06:11

回答

30

在這裏你去。關鍵字是「數組初始化器」。

http://msdn.microsoft.com/en-us/library/aa664573(v=vs.71).aspx

或者說 「集合初始化」

http://msdn.microsoft.com/en-us/library/bb384062.aspx

+1

謝謝。我發現這些集合初始值設定項是實現「iEnumerable」的任何類的標準。# – maxp 2012-02-24 18:53:58

+0

在第二個鏈接上的社區內容討論了一點...不能確認......等等,是的,文檔中有說明。 – mindandmedia 2012-02-24 18:55:58

+3

@maxp這是不正確的。編譯器將集合初始化器轉換爲對類型的Add方法的調用(有關更多詳細信息,請參閱我的答案)。一個類型可以在沒有Add方法的情況下實現IEnumerable;集合初始化器不能與該類型一起使用。例如,'System.String'實現IEnumerable,但沒有'Add'方法。 – phoog 2012-02-24 18:56:34

16

這是一個集合初始化http://msdn.microsoft.com/en-us/library/bb384062.aspx

所以初始化必須實現IEnumerable,並有Add方法的類型。花括號列表中的項目傳遞給add方法;列表中的不同項目可以傳遞給不同的Add方法。如果有超過一個參數的Add重載,則將多個參數放在用大括號括起來的以逗號分隔的列表中。

例如:

class MyWeirdCollection : IEnumerable 
{ 
    public void Add(int i) { /*...*/ } 
    public void Add(string s) { /*...*/ } 
    public void Add(int i, string s) { /*...*/ } 

    //IEnumerable implementation omitted for brevity 
} 

這個類可以這樣初始化:

var weird = new MyWeirdCollection { 1, "Something", {5, "Something else"} }; 

這編譯成類似這樣:

var temp = new MyWeirdCollection(); 
temp.Add(1); 
temp.Add("Something"); 
temp.Add(5, "Something else"); 
var weird = temp; 

his blog post(鏈接張貼埃裏克利珀在評論中),Mads Torgersen簡潔地表達了這一點:

您提供的列表不是「要添加的元素列表」,而是「添加方法的參數集列表」。 ... [W]對列表中的每個條目執行單獨的重載解析和Add方法。

+0

+1這是一個很好的例子! – dasblinkenlight 2012-02-24 18:57:32

+0

這段代碼不會編譯。 '無法使用集合初始值設定項初始化'MyWeirdCollection'類型,因爲它沒有實現'System.Collections.IEnumerable' – maxp 2012-02-24 19:00:07

+0

什麼版本的C#是這樣的? – mindandmedia 2012-02-24 19:07:17

2

這是一個collection initializer。您可以使用Add方法在集合上使用它。

大括號之前的括號是可選的。

這是非常方便的,因爲你可以在詞典使用上比列出了其他集合,例如:

var x = new Dictionary<int,string> {{1, "hello"}, {2, "world"}}; 

這可以讓你避免冗長的初始化序列:

var x = new Dictionary<int,string>(); 
x.Add(1, "hello"); 
x.Add(2, "world"); 
2

在你提供的第三行代碼是創建一個新的字符串數組,然後將該字符串數組傳遞給列表。該列表然後將這些項目中的每一個添加到列表中。這涉及分配數組,額外的開銷,填充它,然後丟棄它。

有一種類定義如何使用集合初始化器來填充自己的機制。 (請參閱其他答案)我從來沒有發現需要將它用於我自己的類,但現有的數據結構(如List,Dictionary)通常會定義它們,並且它們對於使用它們很有用。

36

正如其他人指出的那樣,這是一個集合初始值設定項。您可能不知道的其他一些功能已添加到C#3中:

  • 如果參數列表爲空,則集合初始值設定項構造函數可能會省略括號。所以new List<int> { 10, 20, 30 }沒問題。
  • 使用數組初始值設定項初始化的數組在某些情況下可能會省略該類型。例如,var myInts = new[] { 10, 20, 30};推斷myIntsint[]
  • 對象可以使用類似的對象初始化程序語法進行初始化。 var c = new Customer() { Name = "Fred" };相同var temp = new Customer(); temp.Name = "Fred"; var c = temp;

這些特徵的要點是:(1)使更多的東西,用於需要語句轉換爲僅需要表達的東西; LINQ喜歡把東西當成表達式,(2)啓用更豐富的類型推斷,特別是對於匿名類型。

最後:關於集合初始值設定項所需要的一些答案和評論存在一些混淆。與集合一起使用初始化的類型必須(1)實施IEnumerable(讓我們知道這是一個集合)和(2)具有Add方法(這樣我們可以添加的東西給它。)

http://blogs.msdn.com/b/madst/archive/2006/10/10/what-is-a-collection_3f00_.aspx

有關該功能設計的其他想法。

相關問題