2009-01-19 60 views
55

我一直在尋找在C#集合初始化,發現實施是非常務實的,但也很不像在C#別的爲什麼C#集合初始化器以這種方式工作?

我可以這樣創建代碼:

using System; 
using System.Collections; 

class Program 
{ 
    static void Main() 
    { 
     Test test = new Test { 1, 2, 3 }; 
    } 
} 

class Test : IEnumerable 
{ 
    public IEnumerator GetEnumerator() 
    { 
     throw new NotImplementedException(); 
    } 

    public void Add(int i) { } 
} 

既然我已經滿足了編譯器的最低要求(實現IEnumerablepublic void Add)這個工作,但顯然沒有價值。

我想知道是什麼阻止了C#團隊創建一組更嚴格的要求?換句話說,爲了編譯此語法,編譯器不要求該類型實現ICollection?這似乎更符合其他C#特性的精神。

+3

請注意Web開發人員:如果您試圖將該類的實例序列化爲JSON(實現IEnumerable會導致序列化程序遍歷該對象),將引發NotImplementedException – diachedelic 2012-08-28 06:10:34

回答

87

您的觀察是現場 - 事實上,它反映了由Microsoft C#語言PM的Mads Torgersen製作的一個。

的Mads 2006年10月發了一個帖子關於這個問題的標題What Is a Collection?中,他寫道:

錄取,我們有 System.Collections.ICollection自爆在第一 版本的框架,其中 是無用的。但是,我們固定起來 相當不錯,當仿製藥一起 在.NET Framework 2.0中傳來: 了System.Collections.Generic.ICollection < T> ,您可以添加和刪除元素, 列舉出來,計數和檢查 會員資格。

從此

顯然,每個人都會 實現每次 ICollection的<牛逼>他們提出了一個集合,對不對?並非如此。 以下是我們如何使用LINQ學習 關於什麼樣的集合,以及 如何讓我們在C#3.0中更改我們的語言 設計。

事實證明,有在框架中只有14 ICollection<T>實現,但實現IEnumerable和具有公共Add()方法189班。

這種方法有一個隱藏的好處 - 如果他們已將其基於ICollection<T>接口,那麼將只有一個支持Add()方法。

相反,他們採取的方法意味着集合的初始化器只是爲Add()方法形成參數集。

爲了說明這一點,讓我們稍稍伸出你的代碼:

class Test : IEnumerable 
{ 
    public IEnumerator GetEnumerator() 
    { 
     throw new NotImplementedException(); 
    } 

    public void Add(int i) { } 

    public void Add(int i, string s) { } 
} 

現在你可以這樣寫:

class Program 
{ 
    static void Main() 
    { 
     Test test 
      = new Test 
      { 
       1, 
       { 2, "two" }, 
       3 
      }; 
    } 
} 
+0

在引用中,第二段第一行是「ICollection 」不是「ICollection」。 – 2009-09-25 22:33:49

+0

你是對的 - 我忽略了編碼小於和大於的字符。固定。 – Bevan 2009-09-27 05:13:13

+0

你的答案體現了它提供的好處/靈活性,但我不得不懷疑這是否意味着在類似的情況下沒有提供這種靈活性的有效方法。他們有效地寫入了規範「如果你碰巧在實現IEnumerable的層次結構中有一個名爲`Add`的方法,那麼我們將在編譯器中做一些hokus-pokus並且有初始化器調用它,即使方法是不是重載,接口成員,或者通過語法,屬性或其他方式以任何方式指定用於這種目的。「 – AaronLS 2015-04-01 21:34:39

9

我想過這個過了,它滿足了我最多的就是ICollection的答案除Add之外還有許多其他方法,例如:Clear,Contains,CopyTo和Remove。刪除元素或清除與能夠支持對象初始化器語法無關,只需要一個Add()。

如果框架的設計足夠精細,並且有一個ICollectionAdd接口,那麼它會有一個「完美」的設計。但我真的不認爲這會增加很多價值,每個接口都有一個方法。 IEnumerable + Add似乎是一種駭人聽聞的方式,但是當您考慮它時,這是一個更好的選擇。

編輯:這不是唯一的時間C#已經接近這種類型的解決方案的問題。從.NET 1.1開始,foreach使用duck typing來枚舉集合,所有類需要實現的是GetEnumerator,MoveNext和Current。 Kirill Osenkov也有一個post,它也會問你的問題。

3

(我知道我晚了3年的,但我並不滿足於現有的答案。)

爲什麼,爲了這個語法編譯,該編譯器不 要求的鍵入工具ICollection?

我會逆轉你的問題:如果編譯器有非真正需要的需求,會有什麼用?

ICollection類也可以從集合初始化器語法中受益。考慮允許向其添加數據的類,而不允許訪問先前添加的數據。

就我個人而言,我喜歡使用new Data { { ..., ... }, ... }語法爲我的單元測試的代碼添加一個類似DSL的外觀。

實際上,我寧願削弱這個需求,這樣我就可以使用漂亮的語法,甚至不必執行IEnumerable。集合初始化器是Add()的純語法糖,它們不需要其他任何東西。