Pokyny pro kolekce
Poznámka:
Tento obsah je znovu vytištěn oprávněním Pearson Education, Inc. z Framework Design Guidelines: Conventions, Idioms a Patterns for Reusable .NET Libraries, 2. vydání. Tato edice byla publikována v roce 2008 a kniha byla od té doby plně upravena ve třetím vydání. Některé informace na této stránce můžou být zastaralé.
Každý typ navržený speciálně pro manipulaci se skupinou objektů, které mají určitou společnou charakteristiku, lze považovat za kolekci. Téměř vždy je vhodné, aby takové typy implementovaly IEnumerable nebo IEnumerable<T>, takže v této části považujeme pouze typy implementují jedno nebo obě tato rozhraní jako kolekce.
❌ NEPOUŽÍVEJTE slabě typované kolekce ve veřejných rozhraních API.
Typ všech vrácených hodnot a parametrů představujících položky kolekce by měl být přesným typem položky, nikoli žádným ze základních typů (to platí jenom pro veřejné členy kolekce).
❌ NEPOUŽÍVEJTE ArrayList ani List<T> ve veřejných rozhraních API.
Tyto typy jsou datové struktury navržené tak, aby se používaly v interní implementaci, ne ve veřejných rozhraních API. List<T>
je optimalizovaná pro výkon a výkon za cenu čistoty rozhraní API a flexibility. Pokud se například vrátíte List<T>
, nebudete moci dostávat oznámení, když kód klienta změní kolekci. List<T>
Zpřístupňuje také mnoho členů, například BinarySearch, které nejsou užitečné nebo použitelné v mnoha scénářích. Následující dvě části popisují typy (abstrakce) navržené speciálně pro použití ve veřejných rozhraních API.
❌ NEPOUŽÍVEJTE Hashtable
ani Dictionary<TKey,TValue>
ve veřejných rozhraních API.
Tyto typy jsou datové struktury navržené tak, aby se používaly v interní implementaci. Veřejná rozhraní API by měla používat IDictionary, IDictionary <TKey, TValue>
nebo vlastní typ, který implementuje jedno nebo obě rozhraní.
❌ NEPOUŽÍVEJTE IEnumerator<T>, IEnumeratornebo jakýkoli jiný typ, který implementuje některé z těchto rozhraní, s výjimkou návratového GetEnumerator
typu metody.
Typy vracející enumerátory z jiných metod, než GetEnumerator
nelze použít s příkazem foreach
.
❌ NEimplementujte oba IEnumerator<T>
i IEnumerable<T>
ve stejném typu. Totéž platí pro negenerická rozhraní IEnumerator
a IEnumerable
.
Parametry kolekce
✔️ Jako typ parametru použijte nejméně specializovaný typ. Většina členů přebírá kolekce jako parametry IEnumerable<T>
rozhraní.
❌ Vyhněte se použití ICollection<T> nebo ICollection jako parametr pouze pro přístup Count
k vlastnosti.
Místo toho zvažte použití IEnumerable<T>
nebo IEnumerable
a dynamické kontroly, zda objekt implementuje ICollection<T>
nebo ICollection
.
Vlastnosti kolekce a návratové hodnoty
❌ DO NOT provide settable collection properties.
Uživatelé můžou obsah kolekce nahradit tak, že nejprve vymažou kolekci a pak přidají nový obsah. Pokud je nahrazení celé kolekce běžným scénářem, zvažte poskytnutí AddRange
metody v kolekci.
✔️ Do use Collection<T>
or a subclass of Collection<T>
for properties or return values representing read/write collections.
Pokud Collection<T>
některý požadavek nesplňuje (např. kolekce nesmí implementovat IList), použijte vlastní kolekci implementací IEnumerable<T>
, ICollection<T>
nebo IList<T>.
✔️ Použijte ReadOnlyCollection<T>podtřídu ReadOnlyCollection<T>
nebo ve výjimečných případech IEnumerable<T>
pro vlastnosti nebo návratové hodnoty představující kolekce jen pro čtení.
Obecně, raději ReadOnlyCollection<T>
. Pokud nesplňuje určitý požadavek (např. kolekce nesmí implementovat IList
), použijte vlastní kolekci implementací IEnumerable<T>
, ICollection<T>
nebo IList<T>
. Pokud implementujete vlastní kolekci jen pro čtení, implementujte ICollection<T>.IsReadOnly
vrácení true
.
V případech, kdy jste si jisti, že jediný scénář, který budete chtít podporovat, je iterace pouze vpřed, můžete jednoduše použít IEnumerable<T>
.
✔️ ZVAŽTE použití podtříd obecných základních kolekcí místo použití kolekcí přímo.
To umožňuje lepší název a přidání pomocných členů, které nejsou přítomné na základních typech kolekcí. To platí zejména pro rozhraní API vysoké úrovně.
✔️ ZVAŽTE vrácení podtřídy Collection<T>
nebo ReadOnlyCollection<T>
z velmi běžně používaných metod a vlastností.
To vám umožní přidat pomocné metody nebo změnit implementaci kolekce v budoucnu.
✔️ Zvažte použití kolekce s klíči, pokud položky uložené v kolekci mají jedinečné klíče (názvy, ID atd.). Kolekce s klíči jsou kolekce, které lze indexovat pomocí celého čísla i klíče a jsou obvykle implementovány děděním z KeyedCollection<TKey,TItem>
.
Kolekce s klíči obvykle mají větší nároky na paměť a neměly by se používat, pokud režie paměti převáží nad výhodami použití klíčů.
❌ NEvrací hodnoty null z vlastností kolekce nebo metod vracejících kolekce. Vrátí prázdnou kolekci nebo prázdné pole.
Obecné pravidlo je, že kolekce nebo pole s hodnotou null a prázdné (0 položek) by se měly považovat za stejné.
Snímky versus živé kolekce
Kolekce představující stav v určitém okamžiku se nazývají kolekce snímků. Například kolekce obsahující řádky vrácené z databázového dotazu by byla snímek. Kolekce, které vždy představují aktuální stav, se nazývají živé kolekce. Například kolekce ComboBox
položek je živá kolekce.
❌ NEvrací kolekce snímků z vlastností. Vlastnosti by měly vracet živé kolekce.
Objekty getters by měly být velmi jednoduché operace. Vrácení snímku vyžaduje vytvoření kopie interní kolekce v operaci O(n).
✔️ Použijte buď kolekci snímků, nebo živou IEnumerable<T>
(nebo její podtyp) k reprezentaci kolekcí, které jsou nestálé (tj. mohou se měnit bez explicitní úpravy kolekce).
Obecně platí, že všechny kolekce představující sdílený prostředek (např. soubory v adresáři) jsou nestálé. Takové kolekce jsou velmi obtížné nebo nemožné implementovat jako živé kolekce, pokud implementace není jednoduše enumerátor jen pro předávání.
Volba mezi poli a kolekcemi
✔️ Upřednostňujte kolekce před poli.
Kolekce poskytují větší kontrolu nad obsahem, můžou se v průběhu času vyvíjet a jsou lépe použitelné. Použití polí pro scénáře jen pro čtení se navíc nedoporučuje, protože náklady na klonování pole jsou zakázané. Studie použitelnosti ukázaly, že někteří vývojáři cítí pohodlnější používání rozhraní API založených na kolekcích.
Pokud ale vyvíjíte rozhraní API nízké úrovně, může být vhodnější použít pole pro scénáře čtení i zápisu. Pole mají menší nároky na paměť, což pomáhá snížit pracovní sadu a přístup k prvkům v poli je rychlejší, protože je optimalizovaný modulem runtime.
✔️ ZVAŽTE použití polí v rozhraních API nízké úrovně, abyste minimalizovali spotřebu paměti a maximalizovali výkon.
✔️ Místo kolekcí bajtů používejte bajtová pole.
❌ Nepoužívejte pole pro vlastnosti, pokud by vlastnost musela vrátit novou matici (např. kopii interního pole) při každém zavolání metody getter vlastnosti.
Implementace vlastních kolekcí
✔️ ZVAŽTE dědění z Collection<T>
, ReadOnlyCollection<T>
nebo KeyedCollection<TKey,TItem>
při návrhu nových kolekcí.
✔️ Implementujte IEnumerable<T>
při návrhu nových kolekcí. Zvažte implementaci ICollection<T>
nebo dokonce IList<T>
tam, kde to dává smysl.
Při implementaci takové vlastní kolekce dodržujte vzor rozhraní API vytvořený Collection<T>
a ReadOnlyCollection<T>
co nejblíže. To znamená, že implementujte stejné členy explicitně, pojmenujte parametry, jako jsou tyto dvě kolekce, a tak dále.
✔️ ZVAŽTE implementaci negenerických rozhraní kolekce (IList
a ICollection
), pokud se kolekce často předává rozhraním API, která tato rozhraní přebírají jako vstup.
❌ Vyhněte se implementaci rozhraní kolekcí u typů s komplexními rozhraními API nesouvisejícími s konceptem kolekce.
❌ NEDědí z negenerických základních kolekcí, jako CollectionBase
je . Použijte Collection<T>
, ReadOnlyCollection<T>
a KeyedCollection<TKey,TItem>
místo toho.
Pojmenování vlastních kolekcí
Kolekce (typy, které implementují IEnumerable
) se vytvářejí hlavně ze dvou důvodů: (1) k vytvoření nové datové struktury s operacemi specifickými pro strukturu a často různých charakteristik výkonu než existující datové struktury (např List<T>. , , LinkedList<T>), Stack<T>a (2) pro vytvoření specializované kolekce pro uchovávání konkrétní sady položek (např StringCollection. ). Datové struktury se nejčastěji používají v interní implementaci aplikací a knihoven. Specializované kolekce se dají zpřístupnit hlavně v rozhraních API (jako vlastnosti a typy parametrů).
✔️ Použijte příponu "Slovník" v názvech abstrakcí implementovaných IDictionary
nebo IDictionary<TKey,TValue>
.
✔️ Do use the "Collection" přípony in names of types implement ( IEnumerable
or any of its descendants) and representing a list of items.
✔️ Použijte vhodný název datové struktury pro vlastní datové struktury.
❌ NEPOUŽÍVEJTE žádné přípony, které naznačují konkrétní implementaci, například "LinkedList" nebo "Hashtable", v názvech abstrakcí kolekce.
✔️ ZVAŽTE předponu názvů kolekcí s názvem typu položky. Například kolekce, do které se ukládají položky typu Address
(implementace IEnumerable<Address>
), by měla mít název AddressCollection
. Pokud je typ položky rozhraní, je možné vynechat předponu "I" typu položky. Proto lze volat DisposableCollection
kolekci IDisposable položek .
✔️ Zvažte použití předpony ReadOnly v názvech kolekcí jen pro čtení, pokud by v rámci architektury mohla být přidána odpovídající zapisovatelná kolekce nebo již existuje.
Například kolekce řetězců jen pro čtení by měla být volána ReadOnlyStringCollection
.
© Části 2005, 2009 Microsoft Corporation. Všechna práva vyhrazena.
Reprinted by permission of Pearson Education, Inc. from Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries, 2nd Edition by Krzysztof Cwalina and Brad Abrams, published Oct 22, 2008 by Addison-Wesley Professional v rámci Microsoft Windows Development Series.