2013-04-23 13 views
7

Wenn Sie das Objekt Dictionary<k, v> myDictionary haben, wird myDictionary.Values vom Typ Dictionary<k, v>.ValueCollection und myDictionary.Keys vom Typ Dictionary<k, v>.KeyCollection sein.Welchen Typ sollte myCustomDictionary.Values ​​zurückgeben?

Ich verstehe nicht, warum der Typ myDictionary.Values nicht etwas wie IEnumerable<v>, IList<v> oder etwas anderes ist.

Nun, in diesem Sinne, wenn ich eine benutzerdefinierte Art von Wörterbuch erstellen; Dictionary2<k1, k2, v>, sollte myCustomDictionary.Values eine IEnumerable<v> zurückgeben, oder ein benutzerdefiniertes Implementieren von ValueCollection? Noch wichtiger, warum?

+2

Sehr interessante Frage :) –

Antwort

5

Beachten Sie, dass Dictionary<TKey, TValue>.ValueCollection tatsächlich ICollection<TValue> und damit auch IEnumerable<TValue> implementiert.

Der Grund, warum die Eigenschaft die Art und Weise ist es aus Performance-Gründen wahrscheinlich ist, eingegeben ist: da die Methoden dieser Klasse nicht virtuell sind, können sie genau während JIT-Kompilierung aufgelöst werden, stattdessen VTable-Lookups für jede Methode zu benötigen zur Laufzeit aufrufen. Dadurch wird eine Ebene der Indirektion von jeder Methode entfernt, die Sie für die Auflistung aufrufen. (Es gibt dem JIT auch die Möglichkeit, diese Methodenaufrufe zu inline zu setzen!)

Natürlich können Sie das Objekt bei Bedarf implizit in ICollection<TValue> konvertieren, also gibt es hier keinen Funktionsverlust, nur ein bisschen (Mikro-) Optimierung .

In Ihrem Fall gibt es keinen Grund, dass Sie ICollection<TValue> nicht zurückgeben können, aber Sie können einen spezifischeren Typ zurückgeben, wenn Sie möchten. Wenn Sie das tun, dann müssen Sie explizit die Schnittstelle Eigenschaft implementieren IDictionary<TKey, TValue>.Values die Schnittstelle zu erfüllen:

private ValueCollection valueCollection; 

public ValueCollection Values 
{ 
    get { return valueCollection; } 
} 

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

Dies bedeutet, richtig, dass jeder Leistungsvorteil wird nur für den Verbraucher der Klasse gegeben werden, wenn sie eine Referenz verwenden getippt als Ihr Sammlertyp; Es wird keinen Leistungsvorteil geben, wenn sie sich auf IDictionary<TKey, TValue> beziehen, da sie die Wahl haben, aber dennoch auf Ihre Wertesammlung über ICollection<TValue> zuzugreifen.

In meiner Arbeit habe ich den Leistungsunterschied nicht als signifikant genug gefunden, um etwas Spezifischeres als ICollection<TValue> zurückgeben zu können. Denken Sie daran: immer Benchmark, und niemals vorzeitig optimieren.

+1

Was, diese Antwort hat eine Menge Informationen drin. Vielen Dank Herr! – Tipx

+0

'Liste ' und 'Dictionary ' sind die am häufigsten verwendeten Implementierungen von 'IList ' und 'IDictionary '. Daher hat das Verhindern unnötiger Interface-Dispatch-Aufrufe einen aggregierten Effekt über das gesamte .NET-Ökosystem und trägt zu einem Leistungsvorteil für Mobilgeräte bei, den Java niemals erreichen kann (aufgrund ihrer übermäßigen Verwendung von überschreibbaren Methoden in Infrastrukturklassen). –

1

Dictionary<k, v>.ValueCollection implementiert IEnumerable<v> und Dictionary<k, v>.KeyCollection implementiert IEnumerable<k>. Es ist nicht so, dass die zurückgegebenen Ergebnisse nicht aufzählbar sind.

Durch das Zurückgeben einer tatsächlichen Klasse, die IEnumerable implementiert, anstatt das Ergebnis als IEnumerable einzugeben, haben sie die Möglichkeit, ein wenig zusätzliche Funktionalität einzuschließen. Zum Beispiel haben beide Sammlungen eine Count Eigenschaft, die von keiner IEnumerable leicht zugänglich ist.

+2

Beachten Sie, dass 'ICollection ' eine Count-Eigenschaft hat und 'IDictionary .Values ​​'gibt eine' ICollection 'zurück. Also * irgendeine * Implementierung von 'IDictionary '* muss * ein' Values'-Objekt zurückgeben, das die 'Count' -Eigenschaft trotzdem unterstützt. Der spezifischere Typ von 'Dictionary .Values ​​'bietet in keiner Weise zusätzliche Funktionalität, die ich sehen kann. – cdhowie

Verwandte Themen