Obecné třídy (Průvodce programováním v C#)
Obecné třídy zapouzdřují operace, které nejsou specifické pro konkrétní datový typ. Nejběžnější použití pro obecné třídy je kolekce, jako jsou propojené seznamy, zatřiďovací tabulky, zásobníky, fronty, stromy a tak dále. Operace, jako je přidání a odebrání položek z kolekce, jsou prováděny v podstatě stejným způsobem bez ohledu na typ uložených dat.
Pro většinu scénářů, které vyžadují třídy kolekcí, je doporučeným přístupem použití těch, které jsou k dispozici v knihovně tříd .NET. Další informace o použití těchto tříd naleznete v tématu Obecné kolekce v rozhraní .NET.
Obvykle vytvoříte obecné třídy pomocí existující konkrétní třídy a změnou typů na parametry typu po jednom, dokud nedosáhnete optimálního vyvážení generalizace a použitelnosti. Při vytváření vlastních obecných tříd jsou důležité důležité informace, které zahrnují následující:
Typy, které se mají zobecnit do parametrů typu
Jako pravidlo, čím více typů můžete parametrizovat, tím flexibilnější a opakovaně použitelný kód se stane. Příliš mnoho generalizace však může vytvořit kód, který je obtížné pro ostatní vývojáře ke čtení nebo pochopení.
Jaká omezení se mají použít pro parametry typu (viz omezení u parametrů typu).
Dobrým pravidlem je použít maximální možné omezení, které vám pořád umožní zpracovat typy, které musíte zpracovat. Například pokud víte, že vaše obecná třída je určena pouze pro použití s odkazovým typem, použijte omezení třídy. Tím zabráníte nezamýšlenému použití vaší třídy s typy hodnot a umožní vám použít
asoperátor na aTVyhledat hodnoty null.Určuje, zda se má faktorovat obecné chování pro základní třídy a podtřídy.
Vzhledem k tomu, že obecné třídy mohou sloužit jako základní třídy, platí stejné požadavky na návrh jako u neobecné třídy. Přečtěte si pravidla o dědění z obecných základních tříd dále v tomto tématu.
Zda má být implementováno jedno nebo více obecných rozhraní.
Například pokud navrhujete třídu, která bude použita k vytváření položek v obecných typech kolekce, bude pravděpodobně nutné implementovat rozhraní, například, IComparable<T> kde
Tje typ vaší třídy.
Příklad jednoduché obecné třídy naleznete v tématu Úvod do obecných typů.
Pravidla pro parametry typu a omezení mají několik důsledků pro chování obecné třídy, zejména týkající se dědičnosti a přístupnosti členů. Než budete pokračovat, měli byste pochopit určité výrazy. Pro Node<T>, klientský kód obecné třídy může odkazovat na třídu buď zadáním argumentu typu, pro vytvoření uzavřeného konstruovaného typu ( Node<int> ). Alternativně může ponechat parametr typu neurčeno, například při zadání obecné základní třídy pro vytvoření otevřeného konstruovaného typu ( Node<T> ). Obecné třídy mohou dědit od konkrétních, uzavřených nebo otevřených základních tříd:
class BaseNode { }
class BaseNodeGeneric<T> { }
// concrete type
class NodeConcrete<T> : BaseNode { }
//closed constructed type
class NodeClosed<T> : BaseNodeGeneric<int> { }
//open constructed type
class NodeOpen<T> : BaseNodeGeneric<T> { }
Neobecná, jinak řečeno, konkrétní třídy mohou dědit z uzavřených konstruovaných tříd, ale nikoli z otevřených konstruovaných tříd nebo z parametrů typu, protože v době spuštění pro kód klienta není žádný způsob, jak zadat argument typu vyžadovaný pro vytvoření instance základní třídy.
//No error
class Node1 : BaseNodeGeneric<int> { }
//Generates an error
//class Node2 : BaseNodeGeneric<T> {}
//Generates an error
//class Node3 : T {}
Obecné třídy, které dědí z otevřených konstruovaných typů musí zadat argumenty typu pro všechny parametry typu základní třídy, které nejsou sdíleny třídou dědění, jak je znázorněno v následujícím kódu:
class BaseNodeMultiple<T, U> { }
//No error
class Node4<T> : BaseNodeMultiple<T, int> { }
//No error
class Node5<T, U> : BaseNodeMultiple<T, U> { }
//Generates an error
//class Node6<T> : BaseNodeMultiple<T, U> {}
Obecné třídy, které dědí z otevřených konstruovaných typů musí určovat omezení, která jsou nadmnožinou, nebo implikuje omezení základního typu:
class NodeItem<T> where T : System.IComparable<T>, new() { }
class SpecialNodeItem<T> : NodeItem<T> where T : System.IComparable<T>, new() { }
Obecné typy mohou použít vícenásobné parametry typu a omezení, a to následujícím způsobem:
class SuperKeyType<K, V, U>
where U : System.IComparable<U>
where V : new()
{ }
Otevřené a uzavřené konstruované typy lze použít jako parametry metody:
void Swap<T>(List<T> list1, List<T> list2)
{
//code to swap items
}
void Swap(List<int> list1, List<int> list2)
{
//code to swap items
}
Pokud Obecná třída implementuje rozhraní, všechny instance této třídy lze přetypovat na toto rozhraní.
Obecné třídy jsou invariantní. Jinými slovy, pokud vstupní parametr určuje, zobrazí se List<BaseClass> Chyba při kompilaci, pokud se pokusíte zadat List<DerivedClass> .