Richtlinien für Auflistungen
Hinweis
Diese Inhalte wurden mit Genehmigung von Pearson Education, Inc. aus Framework Design Guidelines nachgedruckt: Conventions, Idioms, and Patterns for Reusable .NET Libraries, 2nd Edition. Diese Ausgabe wurde 2008 veröffentlicht, und das Buch wurde seitdem in der dritten Ausgabe vollständig überarbeitet. Einige der Informationen auf dieser Seite sind möglicherweise veraltet.
Alle Typen, die speziell zum Ändern von Objektgruppen mit einem gemeinsamen Merkmal entworfen wurden, können als Auflistung betrachtet werden. Da sich für diese Typen fast immer die Implementierung von IEnumerable oder IEnumerable<T> anbietet, werden in diesem Abschnitt nur Typen berücksichtigt, die eine oder beide dieser Schnittstellen zum Erstellen von Auflistungen implementieren.
❌ Verwenden Sie KEINE schwach typisierten Auflistungen in öffentlichen APIs.
Der Typ aller Rückgabewerte und Parameter zur Darstellung von Auflistungselementen sollte kein Basistyp, sondern der exakte Elementtyp sein (dies gilt nur für öffentliche Member der Auflistung).
❌ Verwenden Sie ArrayList oder List<T> NICHT in öffentlichen APIs.
Bei diesen Typen handelt es sich um Datenstrukturen, die nicht für öffentliche APIs, sondern für die interne Implementierung konzipiert sind. List<T>
ist leistungsoptimiert, weist jedoch eine geringere Übersichtlichkeit der APIs auf und bietet weniger Flexibilität. Wenn Sie z. B. List<T>
zurückgeben, können niemals Benachrichtigungen empfangen werden, wenn die Auflistung durch Clientcode geändert wird. Darüber hinaus macht List<T>
viele Member (z. B. BinarySearch) verfügbar, die in einer Vielzahl von Szenarien nicht nützlich oder anwendbar sind. In den folgenden beiden Abschnitten werden Typen (Abstraktionen) beschrieben, die speziell für die Verwendung in öffentlichen APIs entworfen wurden.
❌ Verwenden Sie Hashtable
oder Dictionary<TKey,TValue>
NICHT in öffentlichen APIs.
Bei diesen Typen handelt es sich um Datenstrukturen, die für die interne Implementierung konzipiert sind. Für öffentliche APIs sollte IDictionary, IDictionary <TKey, TValue>
oder ein benutzerdefinierter Typ verwendet werden, der eine oder beide dieser Schnittstellen implementiert.
❌ Verwenden Sie NICHT IEnumerator<T>, IEnumerator oder einen anderen Typ, der eine dieser Schnittstellen implementiert (mit Ausnahme des Rückgabetyps einer GetEnumerator
-Methode).
Typen, die Enumeratoren aus anderen Methoden als GetEnumerator
zurückgeben, können nicht mit der foreach
-Anweisung verwendet werden.
❌ Implementieren Sie IEnumerator<T>
und IEnumerable<T>
NICHT mit demselben Typ. Gleiches gilt für die nicht generischen Schnittstellen IEnumerator
und IEnumerable
.
Auflistungsparameter
✔️ Verwenden Sie den am geringsten spezialisierten Typ als Parametertyp. Die meisten Member, die Auflistungen als Parameter verwenden, verwenden die IEnumerable<T>
-Schnittstelle.
❌ Vermeiden Sie die Verwendung von ICollection<T> oder ICollection als Parameter, um lediglich auf die Count
-Eigenschaft zuzugreifen.
Ziehen Sie stattdessen die Verwendung von IEnumerable<T>
oder IEnumerable
in Betracht sowie eine dynamische Überprüfung, ob das Objekt ICollection<T>
oder ICollection
implementiert.
Auflistungseigenschaften und Rückgabewerte
❌ Geben Sie KEINE festlegbaren Auflistungseigenschaften an.
Benutzer können den Inhalt der Auflistung ersetzen, indem sie zunächst die Auflistung löschen und dann neue Inhalte hinzufügen. Wenn es häufig zu Szenarien kommt, in denen die gesamte Auflistung ersetzt wird, sollten Sie gegebenenfalls die AddRange
-Methode für die Auflistung angeben.
✔️ Verwenden Sie Collection<T>
oder eine Unterklasse von Collection<T>
für Eigenschaften oder Rückgabewerte, die Lese-/Schreibauflistungen darstellen.
Wenn Collection<T>
eine bestimmte Anforderung nicht erfüllt (wenn die Auflistung z. B. IList nicht implementieren darf), implementieren Sie IEnumerable<T>
, ICollection<T>
oder IList<T>, um eine benutzerdefinierte Auflistung zu verwenden.
✔️ Verwenden Sie ReadOnlyCollection<T>, eine Unterklasse von ReadOnlyCollection<T>
, oder in seltenen Fällen IEnumerable<T>
für Eigenschaften oder Rückgabewerte, die schreibgeschützte Auflistungen darstellen.
Im Allgemeinen sollte bevorzugt ReadOnlyCollection<T>
verwendet werden. Wenn diese Implementierung eine bestimmte Anforderung nicht erfüllt (wenn die Auflistung z. B. IList
nicht implementieren darf), implementieren Sie IEnumerable<T>
, ICollection<T>
, oder IList<T>
, um eine benutzerdefinierte Auflistung zu verwenden. Bei Implementierung einer benutzerdefinierten schreibgeschützten Auflistung implementieren Sie ICollection<T>.IsReadOnly
, um true
zurückzugeben.
In Fällen, in denen Sie sicher sind, dass ausschließlich ein Szenario mit Vorwärtsiteration unterstützt werden muss, können Sie ganz einfach IEnumerable<T>
verwenden.
✔️ Ziehen Sie anstelle einer direkten Verwendung der Auflistungen die Verwendung von Unterklassen generischer Basisauflistungen in Betracht.
Dadurch lassen sich bessere Namen wählen, und Sie können Hilfsmember hinzufügen, die bei den Basisauflistungstypen nicht vorhanden sind. Dies gilt insbesondere für APIs oberer Ebene.
✔️ Ziehen Sie die Rückgabe einer Unterklasse von Collection<T>
oder ReadOnlyCollection<T>
bei sehr häufig verwendeten Methoden und Eigenschaften in Betracht.
Auf diese Weise lassen sich Hilfsmethoden hinzufügen. Außerdem lässt sich die Auflistungsimplementierung in der Zukunft ändern.
✔️ Ziehen Sie die Verwendung einer schlüsselgebundenen Auflistung in Betracht, wenn die in der Auflistung gespeicherten Elemente über eindeutige Schlüssel (Namen, IDs usw.) verfügen. Bei schlüsselgebundenen Auflistungen handelt es sich um Auflistungen, die sowohl mit einer ganzen Zahl als auch mit einem Schlüssel indiziert werden können und üblicherweise implementiert werden, indem sie von KeyedCollection<TKey,TItem>
erben.
Schlüsselgebundene Auflistungen weisen üblicherweise einen höheren Speicherbedarf auf und sollten nicht verwendet werden, wenn die höhere Speicherauslastung die Vorteile der Schlüssel zunichtemacht.
❌ Geben Sie KEINE NULL-Werte aus Auflistungseigenschaften oder Methoden zurück, die Auflistungen zurückgeben. Geben Sie stattdessen eine leere Auflistung oder ein leeres Array zurück.
Allgemein gilt, dass NULL-Auflistungen und -Arrays sowie leere (0 Elemente) Auflistungen oder Arrays identisch behandelt werden sollten.
Momentaufnahmen und Liveauflistungen im Vergleich
Auflistungen, die einen Zustand zu einem bestimmten Zeitpunkt darstellen, werden als Momentaufnahmenauflistungen bezeichnet. Ein Beispiel für eine Momentaufnahme ist eine Auflistung mit Zeilen, die bei einer Datenbankabfrage zurückgegeben werden. Auflistungen, die immer den aktuellen Zustand darstellen, werden als Liveauflistungen bezeichnet. Eine Auflistung mit ComboBox
-Elementen ist z. B. eine Liveauflistung.
❌ Geben Sie KEINE Momentaufnahmenauflistungen aus Eigenschaften zurück. Eigenschaften sollten Liveauflistungen zurückgeben.
Eigenschaftengetter sollten sehr einfache Vorgänge sein. Zum Zurückgeben einer Momentaufnahme muss eine Kopie einer internen Auflistung in einem O(n)-Vorgang erstellt werden.
✔️ Verwenden Sie entweder eine Momentaufnahmenauflistung oder eine Liveauflistung IEnumerable<T>
(oder einen Untertyp), um flüchtige Auflistungen darzustellen (also Auflistungen, die sich ohne explizites Ändern der Auflistung ändern können).
Im Allgemeinen sind alle Auflistungen, die eine gemeinsam genutzte Ressource darstellen (z. B. Dateien in einem Verzeichnis), flüchtige Auflistungen. Diese Art von Auflistungen lassen sich nur schwer oder gar nicht als Liveauflistungen implementieren, sofern es sich bei der Implementierung nicht um einen einfachen Vorwärtsenumerator handelt.
Auswählen zwischen Arrays und Auflistungen
✔️ Ziehen Sie Auflistungen Arrays vor.
Bei Auflistungen lassen sich Inhalte besser kontrollieren und steuern. Außerdem lassen sie sich besser weiterentwickeln, und sie bieten eine höhere Nutzbarkeit. Darüber hinaus sollten Arrays nicht für schreibgeschützte Szenarien verwendet werden, da für das Klonen des Arrays sehr hohe Kosten anfallen. Nutzbarkeitsstudien haben gezeigt, dass einige Entwickler die Verwendung von auflistungsbasierten APIs bevorzugen.
Wenn Sie jedoch APIs unterer Ebene entwickeln, kann die Verwendung von Arrays für Lese-/Schreibszenarien die bessere Lösung sein. Da der Speicherbedarf von Arrays geringer ist, lässt sich der Arbeitssatz verkleinern. Außerdem kann in einem Array schneller auf Elemente zugegriffen werden, da das Array von der Runtime optimiert wird.
✔️ Ziehen Sie die Verwendung von Arrays bei APIs unterer Ebene in Betracht, um den Speicherverbrauch zu minimieren und die Leistung zu optimieren.
✔️ Verwenden Sie Bytearrays anstelle von Byteauflistungen.
❌ Verwenden Sie KEINE Arrays für Eigenschaften, wenn die Eigenschaft bei jedem Aufruf des Eigenschaftengetters ein neues Array zurückgeben müsste (also eine Kopie eines internen Arrays).
Implementieren von benutzerdefinierten Auflistungen
✔️ Ziehen Sie das Erben von Collection<T>
, ReadOnlyCollection<T>
oder KeyedCollection<TKey,TItem>
in Betracht, wenn Sie neue Auflistungen entwerfen.
✔️ Implementieren Sie IEnumerable<T>
, wenn Sie neue Auflistungen entwerfen. Ziehen Sie die Implementierung von ICollection<T>
oder sogar IList<T>
in Betracht, falls dies sinnvoll ist.
Befolgen Sie das von Collection<T>
und ReadOnlyCollection<T>
definierte API-Muster so gut es geht, wenn Sie eine solche benutzerdefinierte Auflistung implementieren. Implementieren Sie also dieselben Member explizit, benennen Sie die Parameter so, wie sie in diesen beiden Auflistungen benannt sind, usw.
✔️ Ziehen Sie die Implementierung nicht generischer Auflistungsschnittstellen (IList
und ICollection
) in Betracht, wenn die Auflistung häufig an APIs übergeben wird, die diese beiden Schnittstellen als Eingabe verwenden.
❌ Vermeiden Sie die Implementierung von Auflistungsschnittstellen bei Typen mit komplexen APIs, die nicht mit dem Konzept einer Auflistung zusammenhängen.
❌ Erben Sie NICHT von nicht generischen Basisauflistungen wie CollectionBase
. Verwenden Sie stattdessen Collection<T>
, ReadOnlyCollection<T>
und KeyedCollection<TKey,TItem>
.
Benennen von benutzerdefinierten Auflistungen
Sammlungen (Typen, die IEnumerable
implementieren) werden primär aus zwei Gründen erstellt: (1) zum Erstellen neuer Datenstrukturen mit strukturspezifischen Vorgängen und häufig anderen Leistungsmerkmalen als vorhandene Datenstrukturen (z. B. List<T>, LinkedList<T>, Stack<T>) sowie (2) zum Erstellen einer spezialisierten Sammlung für einen bestimmten Satz von Elementen (z. B. StringCollection). Datenstrukturen werden meist in der internen Implementierung von Anwendungen und Bibliotheken verwendet. Spezialisierte Auflistungen werden hauptsächlich in APIs verfügbar gemacht (als Eigenschafts- und Parametertypen).
✔️ Verwenden Sie das Suffix „Dictionary“ in Namen von Abstraktionen, die IDictionary
oder IDictionary<TKey,TValue>
implementieren.
✔️ Verwenden Sie das Suffix „Collection“ in Namen von Typen, die IEnumerable
(oder ein Nachfolgerelement) implementieren und eine Liste mit Elementen darstellen.
✔️ Verwenden Sie den geeigneten Datenstrukturnamen für benutzerdefinierte Datenstrukturen.
❌ Vermeiden Sie in Namen von Auflistungsabstraktionen die Verwendung von Suffixen, die eine bestimmte Implementierung implizieren (z. B. „LinkedList“ oder „Hashtable“).
✔️ Ziehen Sie das Verwenden des Namens des Elementtyps als Präfix bei Auflistungsnamen in Betracht. Der Name einer Auflistung zum Speichern von Elementen vom Typ Address
(die IEnumerable<Address>
implementieren) sollte z. B. AddressCollection
lauten. Wenn der Elementtyp eine Schnittstelle ist, kann das Präfix „I“ des Elementtyps ausgelassen werden. Der Name einer Auflistung mit IDisposable-Elementen kann also DisposableCollection
lauten.
✔️ Ziehen Sie die Verwendung des Präfixes „ReadOnly“ bei Namen schreibgeschützter Auflistungen in Betracht, wenn eine entsprechende beschreibbare Auflistung hinzugefügt werden kann oder bereits im Framework vorhanden ist.
Eine schreibgeschützte Auflistung mit Zeichenfolgen sollte z. B. ReadOnlyStringCollection
heißen.
Teile ©2005, 2009 Microsoft Corporation. Alle Rechte vorbehalten.
Nachdruck mit Genehmigung von Pearson Education, Inc aus Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries, 2nd Edition von Krzysztof Cwalina und Brad Abrams, veröffentlicht am 22. Oktober 2008 durch Addison-Wesley Professional als Teil der Microsoft Windows Development Series.