2013-04-23 1 views
7

Если у вас есть объект Dictionary<k, v> myDictionary, то myDictionary.Values будет иметь тип Dictionary<k, v>.ValueCollection и myDictionary.Keys будет иметь тип Dictionary<k, v>.KeyCollection.Какой тип должен вернуть myCustomDictionary.Values?

Я не понимаю, почему тип myDictionary.Values не является чем-то вроде IEnumerable<v>, IList<v> или еще чем-то.

Теперь, имея это в виду, если я создаю пользовательский тип словаря; Dictionary2<k1, k2, v>, должен myCustomDictionary.Values вернуть IEnumerable<v> или пользовательский инструмент ValueCollection? Что еще более важно, почему?

+2

Очень интересный вопрос :) –

ответ

5

Обратите внимание, что Dictionary<TKey, TValue>.ValueCollection действительно осуществляет ICollection<TValue> и, следовательно, также IEnumerable<TValue>.

Причина свойство напечатал так, как это, вероятно, по соображениям производительности: поскольку методы этого класса не являются виртуальными, они могут быть точно решены в ходе JIT компиляции, вместо того, чтобы требовать виртуальные таблицы Lookups для каждого метода вызывать во время выполнения. Это эффективно удаляет один уровень косвенности из каждого метода, который вы вызываете в коллекции. (Он также дает JIT возможность встроить эти вызовы методов!)

Конечно, вы можете неявно преобразовать объект в ICollection<TValue>, если это необходимо, поэтому здесь нет потери функциональности, просто небольшая (микро) оптимизация ,

В вашем случае нет причин, по которым вы не можете вернуть ICollection<TValue>, но вы можете вернуть более конкретный тип, если хотите. Если вы это сделаете, то вам придется явно реализовать свойство интерфейса IDictionary<TKey, TValue>.Values удовлетворить интерфейс:

private ValueCollection valueCollection; 

public ValueCollection Values 
{ 
    get { return valueCollection; } 
} 

ICollection<TValue> IDictionary<TKey, TValue>.Values 
{ 
    get { return valueCollection; } 
} 

Это правильно подразумевает, что любой выигрыш в производительности будет дан только для потребителей класса, если они используют ссылку набранную как ваш тип коллекции; не будет никакого преимущества в производительности, если они возьмут ссылку на IDictionary<TKey, TValue>, так как им придётся выбирать, но чтобы получить доступ к вашей коллекции значений через ICollection<TValue> в любом случае.

В моей работе я не обнаружил, что разница в производительности является достаточно значительной, чтобы гарантировать возврат чего-либо более конкретного, чем ICollection<TValue>. Помните: всегда ориентируйтесь и никогда преждевременно не оптимизируйте.

+1

Что, этот ответ содержит много информации. Большое спасибо, сэр! – Tipx

+0

'Список ' и 'Словарь ' являются наиболее часто используемыми реализациями 'IList ' и 'IDictionary '. Таким образом, предотвращение ненужных вызовов диспетчеризации интерфейсов имеет совокупный эффект во всей экосистеме .NET и способствует повышению мощности мобильного устройства, которое Java никогда не сможет коснуться (из-за чрезмерного использования переопределяемых методов в классах инфраструктуры). –

1

Dictionary<k, v>.ValueCollection инвентарь IEnumerable<v> и Dictionary<k, v>.KeyCollection инвентарь IEnumerable<k>. Это не похоже на то, что возвращаемые результаты не перечислимы.

Вернув фактический класс, который реализует IEnumerable, вместо того, чтобы вводить результат как IEnumerable, у них есть возможность добавить немного дополнительной функциональности. Например, обе коллекции имеют свойство Count, которое нелегко получить из любого IEnumerable.

+2

Обратите внимание, что 'ICollection ' имеет свойство Count, а 'IDictionary .Values' возвращает' ICollection '. Таким образом, * любая * реализация 'IDictionary ' * должна * возвращать объект «Значения», который в любом случае поддерживает свойство «Count». Более специфичный тип словаря .Values' никоим образом не обеспечивает дополнительную функциональность, которую я вижу. – cdhowie