Poznámka
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Vývojáři používají obecné typy po celou dobu v .NET bez ohledu na to, jestli implicitně nebo explicitně. Když používáte LINQ v .NET, všimli jste si někdy, že pracujete s IEnumerable<T>? Nebo pokud jste někdy viděli online ukázku "obecného úložiště" pro komunikaci s databázemi pomocí Entity Framework, viděli jste, že většina metod vrací IQueryable<T>
? Možná jste se divili, co je T v těchto příkladech a proč tam je.
Poprvé představené v rozhraní .NET Framework 2.0 jsou obecné typy v podstatě "šablona kódu", která vývojářům umožňuje definovat datové struktury bezpečné pro typ , aniž by se zavázali k skutečnému datovému typu. Například je List<T>, která lze deklarovat a používat s jakýmkoli typem, například List<int>
, List<string>
nebo List<Person>
.
Abychom pochopili, proč jsou obecné typy užitečné, podívejme se na konkrétní třídu před a po přidání obecných typů: ArrayList. V .NET Framework 1.0 byly prvky ArrayList
typu Object. Jakýkoli prvek přidaný do kolekce byl automaticky převeden na Object
. Totéž by se stalo při čtení prvků ze seznamu. Tento proces se označuje jako boxování a rozbalování a má vliv na výkon. Kromě výkonu ale neexistuje způsob, jak určit typ dat v seznamu v době kompilace, což vede k psaní křehkého kódu. Obecné typy řeší tento problém definováním typu dat, která bude každá instance seznamu obsahovat. Můžete například přidávat pouze celá čísla do List<int>
a pouze osoby do List<Person>
.
Obecné typy jsou k dispozici také během běhu programu. Modul runtime ví, jaký typ datové struktury používáte, a může ho uložit do paměti efektivněji.
Následující příklad je malý program, který ilustruje efektivitu znalosti typu datové struktury za běhu:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
namespace GenericsExample {
class Program {
static void Main(string[] args) {
//generic list
List<int> ListGeneric = new List<int> { 5, 9, 1, 4 };
//non-generic list
ArrayList ListNonGeneric = new ArrayList { 5, 9, 1, 4 };
// timer for generic list sort
Stopwatch s = Stopwatch.StartNew();
ListGeneric.Sort();
s.Stop();
Console.WriteLine($"Generic Sort: {ListGeneric} \n Time taken: {s.Elapsed.TotalMilliseconds}ms");
//timer for non-generic list sort
Stopwatch s2 = Stopwatch.StartNew();
ListNonGeneric.Sort();
s2.Stop();
Console.WriteLine($"Non-Generic Sort: {ListNonGeneric} \n Time taken: {s2.Elapsed.TotalMilliseconds}ms");
Console.ReadLine();
}
}
}
Tento program vytvoří výstup podobný následujícímu:
Generic Sort: System.Collections.Generic.List`1[System.Int32]
Time taken: 0.0034ms
Non-Generic Sort: System.Collections.ArrayList
Time taken: 0.2592ms
První věc, kterou si zde můžete všimnout, je, že řazení obecného seznamu je výrazně rychlejší než řazení ne generického seznamu. Můžete si také všimnout, že typ obecného seznamu je odlišný ([System.Int32]), zatímco typ pro negenerický seznam je zobecněn. Vzhledem k tomu, že modul runtime ví, že obecný List<int>
je typu Int32, může ukládat prvky seznamu do podkladového celočíselného pole v paměti, zatímco obecný typ ArrayList
musí přetypovat každý prvek seznamu na objekt. Jak ukazuje tento příklad, přetypování navíc zabere čas a zpomalí řazení seznamu.
Další výhodou, když runtime zná typ vašeho generického, je lepší zážitek z ladění. Při ladění obecného v jazyce C# víte, jaký typ má každý prvek ve své datové struktuře. Bez obecných typů byste neměli ponětí, jaký typ každý prvek byl.