Általános típusok áttekintése

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-ben használja, észrevette már, hogy dolgozik?IEnumerable<T> Vagy ha valaha is látott egy online mintát egy "általános adattárból", amely az Entity Framework használatával beszél az adatbázisokkal, látta, hogy a legtöbb metódus visszatér 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 adatok 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ípust véglegesítettek volna. Például egy általános gyűjtemény, 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 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 List<int> adhat hozzá, és csak Személyek elemet adhat hozzá List<Person>.

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 bemutatja az adatstruktúra típusának futásidőben való megismerésének hatékonyságá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 az általános típus ismeretében jobb hibakeresési élmény érhető el. Ha egy általános C#-beli hibakeresést használ, 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.

Lásd még