Jegyzet
Az oldalhoz való hozzáférés engedélyezést igényel. Próbálhatod be jelentkezni vagy könyvtárat váltani.
Az oldalhoz való hozzáférés engedélyezést igényel. Megpróbálhatod a könyvtár váltását.
A fejlesztők folyamatosan általános generikusokat használnak a .NET-ben, akár implicit módon, akár explicit módon. Amikor a LINQ-t a .NET-en belül használja, észrevette már, hogy IEnumerable<T>-vel dolgozik? Vagy ha valaha is látott egy online mintát egy "általános adattárból", amely az Entity Framework használatával kapcsolatot létesít az adatbázisokkal, látta, hogy a legtöbb metódus visszaadja IQueryable<T>? Lehet, hogy elgondolkodott azon, hogy mi a T ezekben a példákban, és miért van benne.
A .NET-keretrendszer 2.0-s verzióban először bevezetett általános eszközök lényegében egy "kódsablon", amely lehetővé teszi a fejlesztők számára, hogy típusbiztos adatstruktúrákat definiáljanak anélkül, hogy tényleges adattípusra kötelezték volna magukat. Például egy List<T>, amely bármilyen típussal deklarálható és használható, például List<int>: , List<string>vagy List<Person>.
Annak megértéséhez, hogy miért hasznosak az általánosak, vessünk egy pillantást egy adott osztályra az általános adatok hozzáadása előtt és után: ArrayList. A .NET-keretrendszer 1.0-s verziójában az ArrayList elemek típusa Objectvolt. A gyűjteményhez hozzáadott elemeket a rendszer csendesen átalakította Object-vá. Ugyanez történik a lista elemeinek olvasásakor is. Ezt a folyamatot boxing és unboxing néven ismerjük, és hatással van a teljesítményre. A teljesítményen kívül azonban nem lehet meghatározni a listában szereplő adatok típusát fordításkor, ami némi törékeny kódot tesz lehetővé. Az általánosak úgy oldják meg ezt a problémát, hogy meghatározzák az egyes listapéldányok által tartalmazott adatok típusát. Például csak egész számokat adhat hozzá a List<int>-hez, és csak személyeket a List<Person>-hez.
A generikusok futásidőben is elérhetők. A futtatókörnyezet tudja, milyen típusú adatstruktúrát használ, és hatékonyabban tárolhatja a memóriában.
Az alábbi példa egy kis program, amely azt mutatja be, hogy futásidőben milyen hatékonysággal ismerheti meg az adatstruktúra típusát:
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();
}
}
}
Ez a program a következőhöz hasonló kimenetet hoz létre:
Generic Sort: System.Collections.Generic.List`1[System.Int32]
Time taken: 0.0034ms
Non-Generic Sort: System.Collections.ArrayList
Time taken: 0.2592ms
Az első dolog, amit itt láthat, az az, hogy az általános lista rendezése jelentősen gyorsabb, mint a nem általános lista rendezése. Azt is megfigyelheti, hogy az általános lista típusa eltérő ([System.Int32]), míg a nem általános lista típusa általánosított. Mivel a futtatókörnyezet tudja, hogy az általános List<int> típus Int32, a listaelemeket egy mögöttes egész számtömbben tárolhatja a memóriában, míg a nem általánosaknak ArrayList minden egyes listaelemet egy objektumhoz kell adniuk. Ahogy ez a példa is mutatja, a további szereplők időt vesznek igénybe, és lelassítják a lista rendezését.
A futtatókörnyezet további előnye, hogy a generikus típus ismeretében a jobb hibakeresési élmény érhető el. Amikor egy generikus típussal dolgozik C#-ban, tudja, hogy az egyes elemek milyen típusúak az adatstruktúrában. Általános elemek nélkül fogalma sincs, hogy az egyes elemek milyen típusúak.