Почему IDictionary ‹TKey, TValue› расширяет ICollection ‹KeyValuePair‹ TKey, TValue ››?

Я пытаюсь создать собственный ReadOnlyDictionary<TKey, TValue> для .NET 4.0. Подход состоит в том, чтобы сохранить частный объект Dictionary<TKey, TValue>, а также флаги, чтобы определить, разрешено ли добавление / удаление и назначение элементов.

Это нормально работает, но я хотел реализовать интерфейс IDictionary<TKey, TValue> для полноты. Однако я заметил, что он расширяет ICollection<KeyValuePair<TKey, TValue>>, тогда как ни одно из его свойств или методов не присутствует в классе Dictionary<TKey, TValue>. Как это возможно? Если интерфейс реализован, почему не отображаются ICollection членов?

Кроме того, почему класс Dictionary должен реализовывать ICollection в первую очередь?

Вот примерная реализация:

public sealed class ReadOnlyDictionary<TKey, TValue>:
    //IDictionary<TKey, TValue>,
    IEnumerable<KeyValuePair<TKey, TValue>>
{
    #region Members.

    public bool AllowListEdit { get; private set; }
    public bool AllowItemEdit { get; private set; }
    private Dictionary<TKey, TValue> Dictionary { get; set; }

    #endregion Members.

    #region Constructors.

    public ReadOnlyDictionary (bool allowListEdit, bool allowItemEdit) { this.AllowListEdit = allowListEdit; this.AllowItemEdit = allowItemEdit; this.Dictionary = new Dictionary<TKey, TValue>(); }
    public ReadOnlyDictionary (IEqualityComparer<TKey> comparer, bool allowListEdit, bool allowItemEdit) { this.AllowListEdit = allowListEdit; this.AllowItemEdit = allowItemEdit; this.Dictionary = new Dictionary<TKey, TValue>(comparer); }
    public ReadOnlyDictionary (IDictionary<TKey, TValue> dictionary, bool allowListEdit = false, bool allowItemEdit = false) : this(allowListEdit, allowItemEdit) { foreach (var pair in dictionary) { this.Dictionary.Add(pair.Key, pair.Value); } }
    public ReadOnlyDictionary (IDictionary<TKey, TValue> dictionary, IEqualityComparer<TKey> comparer, bool allowListEdit = false, bool allowItemEdit = false) : this(comparer, allowListEdit, allowItemEdit) { foreach (var pair in dictionary) { this.Dictionary.Add(pair.Key, pair.Value); } }

    #endregion Constructors.

    #region Properties.

    public int Count { get { return (this.Dictionary.Count); } }
    public IEqualityComparer<TKey> Comparer { get { return (this.Dictionary.Comparer); } }

    #endregion Properties.

    #region Methods.

    private void ThrowItemReadOnlyException () { if (this.AllowListEdit) { throw (new NotSupportedException("This collection does not allow editing items.")); } }
    private void ThrowListReadOnlyException () { if (this.AllowItemEdit) { throw (new NotSupportedException("This collection does not allow adding and removing items.")); } }
    public bool ContainsValue (TValue value) { return (this.Dictionary.ContainsValue(value)); }
    public void Clear () { this.ThrowListReadOnlyException(); this.Dictionary.Clear(); }

    #endregion Methods.

    #region Interface Implementation: IEnumerable<KeyValuePair<TKey, TValue>>.

    IEnumerator IEnumerable.GetEnumerator () { return (this.Dictionary.GetEnumerator()); }
    public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator () { return (this.Dictionary.GetEnumerator()); }

    #endregion Interface Implementation: IEnumerable<KeyValuePair<TKey, TValue>>.

    #region Interface Implementation: ICollection<KeyValuePair<TKey, TValue>>.

    //public int Count { get { return (this.Dictionary.Count); } }
    //public bool IsReadOnly { get { return (this.AllowListEdit); } }

    //public bool Contains (KeyValuePair<TKey, TValue> item) { throw (new NotImplementedException()); }
    //public void Clear () { throw (new NotImplementedException()); }
    //public void Add (KeyValuePair<TKey, TValue> item) { throw (new NotImplementedException()); }
    //public void CopyTo (KeyValuePair<TKey, TValue> [] array, int arrayIndex) { throw (new NotImplementedException()); }
    //public bool Remove (KeyValuePair<TKey, TValue> item) { throw (new NotImplementedException()); }

    #endregion Interface Implementation: ICollection<KeyValuePair<TKey, TValue>>.

    #region Interface Implementation: IDictionary<TKey, TValue>.

    //====================================================================================================
    // Interface Implementation: IDictionary<TKey, TValue>.
    //====================================================================================================

    public Dictionary<TKey, TValue>.KeyCollection Keys { get { return (this.Dictionary.Keys); } }
    public Dictionary<TKey, TValue>.ValueCollection Values { get { return (this.Dictionary.Values); } }
    public TValue this [TKey key] { get { return (this.Dictionary [key]); } set { this.ThrowItemReadOnlyException(); this.Dictionary [key] = value; } }

    public void Add (TKey key, TValue value) { this.ThrowListReadOnlyException(); this.Dictionary.Add(key, value); }
    public bool ContainsKey (TKey key) { return (this.Dictionary.ContainsKey(key)); }
    public bool Remove (TKey key) { this.ThrowListReadOnlyException(); return (this.Dictionary.Remove(key)); }
    public bool TryGetValue (TKey key, out TValue value) { return (this.Dictionary.TryGetValue(key, out value)); }

    #endregion Interface Implementation: IDictionary<TKey, TValue>.
}

person Raheel Khan    schedule 28.01.2014    source источник


Ответы (1)


Dictionary<TKey, TValue> реализует ICollection<KeyValuePair<TKey, TValue>> интерфейс явно.

Как вы можете видеть на странице MSDN для Dictionary < / a>, эти методы перечислены в разделе «Явные реализации интерфейса».

Явная реализация интерфейса означает, что эти методы не будут доступны через конкретный тип. Вам нужно будет преобразовать словарь в ICollection<T>, чтобы иметь возможность вызывать их.

Dictionary<int, int> dict = new Dictionary<int, int>();
bool sync = dict.IsSynchronized; // not allowed

ICollection<KeyValuePair<int, int>> dict = new Dictionary<int, int>();
bool sync = dict.IsSynchronized; // allowed

Подробнее о явных реализациях интерфейса: http://msdn.microsoft.com/en-us/library/aa288461(v=vs.71).aspx

person dcastro    schedule 28.01.2014
comment
Спасибо. Я знаю о явных интерфейсах, но не думал об этом. Тогда возникает вопрос, почему словарь вообще должен реализовывать ICollection? IEnumerable уже заботится об итерации, и произвольное добавление KayValuePairs не должно быть разрешено, верно? - person Raheel Khan; 28.01.2014
comment
@RaheelKhan: ну, я тоже не вижу особых преимуществ в реализации ICollection .. Может быть, просто для полноты и согласованности (поскольку почти каждая коллекция в System.Collections расширяет ICollection)? - person dcastro; 28.01.2014
comment
Мех. Я думал, что инициализаторы коллекций будут иметь смысл, но IDictionary уже определяет соответствующий метод Add. Ничего, извините за спам уведомлений. - person Rytmis; 28.01.2014
comment
@dcastro: словарь знает, сколько в нем элементов; ICollection или ICollection<T> может сообщить эту информацию, но IEnumerable<T> не может. Когда был разработан Dictionary, наименее специфичным интерфейсом, унаследованным как от IEnumerable<T>, так и от чего-то с Count методом, был ICollection<T>. - person supercat; 05.11.2014