C#集合--ICollection接口和IList接口

雖然列舉接口提供了一個協議,用於向前的方式遍歷集合,但它們沒有提供一種機制來肯定集合的大小,經過索引訪問集合的成員,搜索集合,或修改集合。爲了實現這些功能,.NET Framework定義了ICollection,IList和IDictionary接口。每一個接口都有Generic的接口和非Generic的接口,請注意非Generic多數用於支持遺留代碼。html

這些接口的繼承掛關係以下圖所示:程序員

image

Generic的接口和非Generic的接口之間的差距超出了你的預期,特別是ICollection和ICollection<T>。這是因爲歷史緣由形成的,由於Generic類型是C# 2.0才引入的,因此Generic吸收了非Generic接口的經驗和教訓,從而設計了與之不一樣的但更優秀的接口。正式因爲這個緣由,ICollection<T>並無派生自ICollection,一樣地,IList<T>也沒有派生自IList, IDictionary<TKey,TValue>也沒有派生自IDinctionary。所以集合類能夠同時實現Generic的接口和非Generic的接口。(事實上,集合類通常都實現了兩個類型接口,好比class Collection<T>: IList<T>, IList,有好比List<T> : IList<T>, System.Collections.IList)。數組

 

ICollection<T>和ICollection

ICollection<T>是能夠統計集合中對象的標準接口。該接口能夠肯定集合的大小(Count),集合是否包含某個元素(Contains),複製集合到另一個數組(ToArray),集合是不是隻讀的(IsReadOnly)。若是一個集合是可編輯的,那麼能夠調用Add,Remove和Clear方法操做集合中的元素。由於該接口繼承IEnumerable<T>,因此可使用foreach語句遍歷集合。該接口的定義以下安全

public interface ICollection<T> : IEnumerable<T>
{
    // Number of items in the collections.        
    int Count { get; }

    bool IsReadOnly { get; }

    void Add(T item);

    void Clear();

    bool Contains(T item); 
            
    // CopyTo copies a collection into an Array, starting at a particular
    // index into the array.
    // 
    void CopyTo(T[] array, int arrayIndex);
            
    //void CopyTo(int sourceIndex, T[] destinationArray, int destinationIndex, int count);

    bool Remove(T item);
}

而非Generic的ICollection定義以下:ui

public interface ICollection : IEnumerable
{   
    void CopyTo(Array array, int index);    
  
    int Count { get; }

    Object SyncRoot { get; }        
   
    bool IsSynchronized { get; }
}

與ICollection<T>相比較,ICollection實現了計算集合元素數目的功能,但明沒有提供更改集合的功能。此外,ICollection還提供了同步的功能。而ICollection<T>則取消了同步的功能,這是由於對於Generic的集合,它們自己是線程安全的。this

這兩個接口既簡單又容易實現。假如要實現一個只讀的ICollection<T>,那麼在Add,Remove,和Clear方法中拋出異常便可。spa

這些接口一般與任何IList或IDictionary接口中的任意一個一塊兒實現。線程

 

IList<T>和IList

若是想經過位置獲取集合元素,那麼IList<T>就是此類集合的標準接口。此外,因爲IList<T>繼承了ICollection<T>和IEnumerable<T>,因此此接口還提供了根據位置讀取或寫入元素,或者在指定的位置插入或刪除元素。IList<T>定義以下設計

public interface IList<T> : ICollection<T>
{
    T this[int index] { get; set; }
    
    int IndexOf(T item);

    void Insert(int index, T item);    
  
    void RemoveAt(int index);
}

IndexOf方法在集合上執行線性搜索,若是沒有發現指定元素,那麼返回-1。3d

List類的IndexOf方法的實現:(List.IndexOf(T item)調用Array.IndexOf(_items, item, index, _size - index),而後調用EqualityComparer<T>.Default.IndexOf(array, value, startIndex, count))

internal virtual int IndexOf(T[] array, T value, int startIndex, int count) {
    int endIndex = startIndex + count;
    for (int i = startIndex; i < endIndex; i++) {
        if (Equals(array[i], value)) return i;
    }
    return -1;
}

而非Generic的IList則包含了更多成員,由於它繼承ICollection

public interface IList : ICollection
{
    Object this[int index] {  get;set; }    
    int Add(Object value);
    bool Contains(Object value);
    void Clear();
    bool IsReadOnly  { get; }
    bool IsFixedSize  { get; }
    int IndexOf(Object value);
    void Insert(int index, Object value);
    void Remove(Object value);
    void RemoveAt(int index);
}

IList接口的Add方法返回一個整數,這是加到集合中元素的位置。而IList<T>接口的Add方法返回值爲空。

C#中,List<T>就是典型的既實現了IList<T>又實現了IList的類。

public class List<T> : IList<T>, System.Collections.IList, IReadOnlyList<T>

C#數組也實現了generic和非generic的IList接口。C#中Array類的部分代碼(實現IList接口的代碼)

public abstract class Array : ICloneable, IList, IStructuralComparable, IStructuralEquatable
{
    ......
    public bool IsReadOnly
    { get { return false; } }

    public bool IsFixedSize
    {
        get { return true; }
    }

    Object IList.this[int index]
    {
        get { return GetValue(index); }
        set { SetValue(value, index); }
    }

    int IList.Add(Object value)
    {
        throw new NotSupportedException(Environment.GetResourceString("NotSupported_FixedSizeCollection"));
    }

    bool IList.Contains(Object value)
    {
        return Array.IndexOf(this, value) >= this.GetLowerBound(0);
    }

    void IList.Clear()
    {
        Array.Clear(this, this.GetLowerBound(0), this.Length);
    }

    int IList.IndexOf(Object value)
    {
        return Array.IndexOf(this, value);
    }

    void IList.Insert(int index, Object value)
    {
        throw new NotSupportedException(Environment.GetResourceString("NotSupported_FixedSizeCollection"));
    }

    void IList.Remove(Object value)
    {
        throw new NotSupportedException(Environment.GetResourceString("NotSupported_FixedSizeCollection"));
    }

    void IList.RemoveAt(int index)
    {
        throw new NotSupportedException(Environment.GetResourceString("NotSupported_FixedSizeCollection"));
    }
    ......
}

而Generic的IList<T>是在sealed class SZArrayHelper中實現的。SZ(Single dimensional, Zero-based)。請注意,若是你在技術與上調用add或者remove方法,那麼會返回NotSupportedException異常

image

 

IReadonlyList<T>

爲了與Windows運行時的制度集合互操做,Framework4.5引入了一個新的集合接口IReadOnlyList<T>。該接口自身就很是有用,也能夠看做IList的縮減版,對外只公開用於只讀的操做。其定義以下:

public interface IReadOnlyCollection<out T> : IEnumerable<T>
{
    int Count { get; }
}

public interface IReadOnlyList<out T> : IReadOnlyCollection<T>
{
    T this[int index] { get; }
}

由於類型參數僅僅用於輸出位置,因此其標記爲協變(covariant)。好比,一個cats列表,能夠看做一個animals的只讀列表。相反,在IList<T>中,T沒有標記爲協變,由於T應用於輸入和輸出位置。

你可能認爲IList<T>派生自IReadonlyList<T>,而後,微軟並無這麼作,這是由於這麼作就要求把IList<T>的成員移動到IReadonlyList<T>,這就給CLR4.5帶來重的變化(程序員須要從新編輯程序以免運行時錯誤)。實際上,微軟在IList<T>的實現類中手動地添加了對IReadonlyList<T>接口的實現。

在Windows運行時中IVectorView<T>與.NET Framework的IReadonlyList<T>相對應。

 

 

參考

線性搜索(Linear Search): http://en.wikipedia.org/wiki/Linear_search; http://blog.teamleadnet.com/2012/02/quicksort-binary-search-and-linear.html

數組實現IList<T>: http://stackoverflow.com/questions/11163297/how-do-arrays-in-c-sharp-partially-implement-ilistt/11164210#11164210

數組的奧祕: http://stackoverflow.com/questions/19914523/mystery-behind-system-array

協變: http://stackoverflow.com/questions/2719954/understanding-covariant-and-contravariant-interfaces-in-c-sharp

相關文章
相關標籤/搜索