2014-10-05 59 views
3

我需要在自己的類中維護集合語義。難道你不能解釋什麼是集合語義?據我所知,它是一組必須在課堂上實施的接口。這是真的嗎?如果是的話 - 什麼恰恰我必須在課堂上實現和爲什麼?這兩個接口(ICollection和IEnumerable)是否足夠,或者這些只是最必要的接口?什麼是集合語義(在.NET中)?

我正在使用this article作爲幫助對一個循環鏈表進行編程。

+0

鏈接的文章已經實現了ICollection。 – 2014-10-05 11:24:54

+0

是的,我知道。這對我來說有點困惑。 @HenkHolterman – 2014-10-05 12:08:05

回答

12

有.NET中許多集合類型,它們都具有一些共同的行爲,例如:

  • 你可以列舉他們使用foreach
  • 他們有一個Count財產
  • 您可以添加使用Add方法
  • 等......

此行爲預期來自集合類型,您猜對了:全部位於ICollection<T>接口中。讓我們來看看接口層次:

  • IEnumerable<T>允許類與foreach
  • ICollection<T>枚舉是IEnumerable<T>代表一個集合:
    • 它允許檢索項目Count
    • 可能可以Add/Remove/Clear收藏品
    • 集合可以是隻讀,在這種情況下IsReadOnly應該返回true
    • 還有幾個其他的輔助方法太:Contains/CopyTo
  • IList<T>是一個ICollection<T>允許通過索引訪問項目。
    • 它增加了一個索引
    • 一些指數相關的功能:Insert/RemoveAt
    • IndexOf

哪些接口應實現是語義問題:

IEnumerable<T>只是一個可枚舉的序列。它只應該通過消費代碼枚舉一次,因爲你永遠不知道它是如何在多個枚舉上表現的。像ReSharper這樣的工具甚至會發出警告,如果您多次枚舉IEnumerable<T>
當然,大多數時候你可以安全地枚舉它多次,但有些時候你不應該這樣做。例如,枚舉可以執行SQL查詢(例如,考慮Linq-to-SQL)。

您通過定義一個函數來實現IEnumerable<T>GetEnumerator返回en IEnumerator<T>。枚舉器是一種對象,它是一種指向序列中當前元素的指針。它可以返回這個值Current,並且它可以移動到MoveNext的下一個元素。它也是一次性的(並且在枚舉結束時由foreach處置)。

讓我們分解一個foreach循環:

IEnumerable<T> sequence = ... // Whatever 
foreach (T item in sequence) 
    DoSomething(item); 

這等同於以下內容:

IEnumerator<T> enumerator = null; 
try 
{ 
    enumerator = sequence.GetEnumerator(); 
    while (enumerator.MoveNext()) 
    { 
     T item = enumerator.Current; 
     DoSomething(item); 
    } 
} 
finally 
{ 
    if (enumerator != null) 
     enumerator.Dispose(); 
} 

爲了記錄在案,實施IEnumerable沒有嚴格要求,使一類可與foreach。鴨子打字在這裏就足夠了,但我太離譜了。

當然,你可以用yield關鍵字很容易地實現模式:

public static IEnumerable<int> GetAnswer() 
{ 
    yield return 42; 
} 

這將創建將實施IEnumerable<int>給你,讓你不必爲私有類。

ICollection<T>代表一個集合,它可以多次安全地枚舉。但你真的不知道它是什麼樣的集合。它可以是一個集合,一個列表,一個字典,不管。

這是集合的語義。

一些例子:

  • T[] - 它實現ICollection<T>即使你不能Add/Remove
  • List<T>
  • HashSet<T> - 集合的一個很好的例子,但不是列表
  • Dictionary<TKey, TValue> - 是的,這是一個ICollection<KeyValuePair<TKey, TValue>>
  • LinkedList<T>
  • ObservableCollection<T>

IList<T>讓你知道的集合是一個可以讓你通過索引訪問元素容易的那種(即在O(1)時間)。

對於您的循環鏈表,情況並非如此,因爲它不僅需要O(n)時間,但首先沒有有意義的索引。

一些例子:

  • T[]
  • List<T>
  • ObservableCollection<T>

注意HashSet<T>Dictionary<TKey, TValue>不再在列表中的實例。這些不是列表。 LinkedList<T>在語義上是一個列表,但它不提供按索引訪問的時間(它需要O(n))。

我應該提到只有在.NET 4.5中寫入的等價物:IReadOnlyCollection<out T>IReadOnlyList<out T>。這些對他們提供的協方差很好。

+0

非常感謝您的詳盡解釋!現在我的想法更清晰了。 – 2014-10-05 12:34:28