A C# programozási nyelv

Sablonok

A generikus típusokat a C# 2.0 tartalmazza először. Ezek révén nincs szükség adatkonverzióra gyűjtemények használata során. A típus biztonság javul, kevesebb bedobozolásra lesz szükség, és egyszerűbb lesz az általános osztályok és metódusok létrehozása. A .NET-keretrendszer 2.0-ás verziója a System.Collections.Generic névtere sok gyűjteményosztályt és interfészt tartalmaz generikus verzióban.

Paraméterek, példányosítás, szintaxis

A típusparamétert relációs jelek közé kell helyeznünk, amikor a változót deklaráljuk. A típus paraméter meghatározza, hogy az objektum milyen típust fogad el.
A metódusok ezután a megadott objektumtípust fogják várni paraméterként. Fontos tudni, hogy a típusparaméter helyettesítése a megadott típussal nem csupán szöveghelyettesítési algoritmus. A fordítóprogram teljes szemantikai behelyettesítést végez, amivel bármilyen érvényes típust megadhatunk a típusparaméternek.

Egy generikus osztály több típusparaméterrel is rendelkezhet. A generikus System.Collections.Generic.Dictionary osztályt például név érték párokkal lehet példányosítani, ezért két típusparamétert fogad el. Ennek megfelelően az osztály definíció a következő alakú:

public class Dictionary<T,U>

Példa a Dictionary osztály példányosítására:

Dictionary<string, int> honapNapjai = new Dictionary<string, int>(); //Deklaráció
honapNapjai.Add("januar",30); //Elem felvétel
honapNapjai["januar"] = 31; //Érték megváltoztatása

Generikus típusok és a megszorítások

Néha szeretnénk tudni, hogy a generikus osztály által használt típusparaméter olyan típust jelöl, amely megfelel bizonyos kritériumoknak, pontosabban rendelkezik néhány szükséges metódussal. Ezt megszorítással biztosíthatjuk. Megszorítással a generikus osztály típusparamétereit olyan típusokra korlátozzuk, amelyek rendelkeznek bizonyos interfész halmazzal és így az interfészek által definiált metódusokat tartalmazzák. Ha például a generikus típusunkban csak ISerializable típusparamétert szeretnénk elfogadni a generikus típusunk definíciója a következő alakú lesz:

public class SerializableCollection<T> where T : ISerializable

Fontosabb elérhető generikus osztályok a System.Collections.Generic névtérben

Generikus típus

Leírás

Dictionary<TKey, TValue>

Név/érték párokat tartalmazó, név szerint indexelt lista.

Dictionary<TKey, TValue>.KeyCollection

A nevek listája.

Dictionary<TKey, TValue>.ValueCollection

Az értékek listája.

HashSet<T>

Értékhalmaz.

LinkedList<T>

Láncoltlista.

LinkedListNode<T>

Láncoltlista egy eleme.

List<T>

Lista.

Queue<T>

Sor.

SortedDictionary<TKey, TValue>

Rendezett név/érték párokat tartalmazó név szerint indexelt lista.

SortedDictionary<TKey, TValue>.KeyCollection

A nevek listája.

SortedDictionary<TKey, TValue>.ValueCollection

Az értékek listája.

SortedList<TKey, TValue>

Rendezett lista, név/érték párokkal.

SortedSet<T>

Halmaz, amelynek elemeire rendezett tárolás van megvalósítva.

Stack<T>

Verem.

Generikus típusok kontra általánosított osztályok

A típusparamétereket használó generikus típus fogalma eltér az általánosított osztály fogalmától. Ez utóbbi olyan paramétereket fogad el, amelyek más típusra konvertálhatóak. A System.Collections névtér általánosított osztályainak egyetlen megvalósítása van, amely System.Object típust fogadnak el és ezzel is térnek vissza. Adatkonverzióval elérhető különböző típusú adatok tárolása ezekben, azonban ettől még egy osztálymegvalósítást használunk ezért ezek nem sablon típusok. A sablont használó osztályokat ezekkel szemben a fordítóprogram olyan típus használatára fogja megvalósítani, amelyet a típusparaméterben megadtunk.

A System.Collections névtér általánosított osztályokkal

A System.Collections névtér segítségével lehetőségünk nyílik a legtöbb közismert adattípus használata. Itt található pl.az egyszerű verem, sor, vagy akár a bonyolultabb rendezett lista. Az alábbi adattípusok vannak közös propertije ill. metódusai (mivel ugyanazokból az interfészekből származnak) pl.:

Stack

Egyszerű firt-in-last-out adattípus. Műveletei az ismert Push, Pop. Viszont Top helyett a Peek metódus tér vissza a verem tetején lévő elemmel.

Stack myStack = new Stack(); //boxing történik itt
myStack.Push(0);
myStack.Push(1);
myStack.Push(2);
myStack.Push(3);
myStack.Push(4);
Console.Write("Visszaszámlálás indul.."); //unboxing
Console.Write((int)myStack.Pop().ToString()+"..");
Console.Write((int)myStack.Pop().ToString()+"..");
Console.Write((int)myStack.Pop().ToString()+"..");
Console.Write((int)myStack.Pop().ToString()+"..");
Console.Write((int)myStack.Pop().ToString()); 

Queue

Egyszerű firt-in-first-out adattípus. Az Enqueue metódussal rakhatunk a sorba egy elemet, a Dequeue metódussal pedig kivehetjük. A Peek metódus tér vissza a sor elején található elemmel. A TrimToSize metódussal, pedig méretre szabhatjuk a sorunkat, csökkentve a jelenlegi elemek számára.

Queue myQueue = new Queue();//boxing történik itt 
myQueue.Enqueue(4);
myQueue.Enqueue(3);
myQueue.Enqueue(2);
myQueue.Enqueue(1);
myQueue.Enqueue(0);
Console.Write("Visszaszámlálás indul..");//unboxing
Console.Write((int)myQueue.Dequeue().ToString()+".."); //4
Console.Write((int)myQueue.Dequeue().ToString()+".."); //3
Console.Write((int)myQueue.Dequeue().ToString()+".."); //2
Console.Write((int)myQueue.Dequeue().ToString()+".."); //1
Console.Write((int)myQueue.Dequeue().ToString()); //0 

ArrayList

Egy tömb típus, aminek a méretét dinamikusan változtathatjuk. Mivel az IList interfészt is implementálja úgy is tekinthetünk rá, mint egy listára. Az Add ill. Insert-tel beszúrhatunk egy elemet a tömb végére vagy valamelyik helyére. A Remove-val kiveszük az adott elem első előfordulási helyéről, a RemoveAt-tel pedig bármelyik indexű helyről. A Sort metódussal egy QuickSort rendezést végezhetünk el a tömbön.

ArrayList myArrayList = new ArrayList();
myArrayList.Add("Hello");
myArrayList.Add("world");
myArrayList.Add("!");
// az ArrayList számossága, kapacitása és értékei
Console.WriteLine("myArrayList");
Console.WriteLine("\tSzámossága: {0}", myArrayList.Count);
Console.WriteLine("\tKapacitása: {0}", myArrayList.Capacity);
Console.Write((string)myArrayList[0]+(string)myArrayList[1]+(string)myArrayList[2]); // Hello world!

BitArray

A BitArray-jel bit tömböt definiálhatunk, amely bool ként van ábrázolva, tehát true, ha 1, false, ha 0. A tömb létrehozásánál el kell döntenünk, hogy mekkora bit tömböt szeretnénk, vagy ha átadunk neki számértékeket, azokat átkonvertálja bitekre. Egy vagy több BitArray között elvégezhetünk megfelelő bitműveleteket, mint a Not, Or, And és a Xor.

// Creates and initializes two BitArrays of the same size.
BitArray myBA1 = new BitArray(4);
BitArray myBA2 = new BitArray(4);
myBA1[0] = myBA1[1] = false; //0
myBA1[2] = myBA1[3] = true; //1
myBA2[0] = myBA2[2] = false; //0
myBA2[1] = myBA2[3] = true; //1 
// Performs a bitwise OR operation between BitArray instances of the same size.
Console.WriteLine( "A myBA1 és a myBA2 értékei:" );
Console.Write("myBA1:");
PrintValues(myBA1, 8); //0011
Console.Write( "myBA2:" );
PrintValues(myBA2, 8); //0101
Console.WriteLine();
Console.WriteLine( "Műveletek" );
Console.Write("OR:");
PrintValues(myBA1.Or( myBA2 ), 8); // 0011 OR 0101
Console.WriteLine();
Console.Write("XOR:")
PrintValues(myBA1.Xor(myBA2), 8); // (0011 OR 0101) XOR 0101
Console.WriteLine()
Console.Write( "AND:" );
PrintValues(myBA1.And(myBA2), 8); // ((0011 OR 0101) XOR 0101) AND 0101
Console.WriteLine(); 
public static void PrintValues( IEnumerable myList, int myWidth )
{
  System.Collections.IEnumerator myEnumerator = myList.GetEnumerator();
  int i = myWidth;
  while ( myEnumerator.MoveNext() )
  {
  if ( i <= 0 )
  {
  i = myWidth;
  Console.WriteLine();
  }
   i--;
  Console.Write( "\t{0}", myEnumerator.Current );
  }
  Console.WriteLine();

}

HashTable

A HashTable egy hash táblát valósít meg, ami egy hash kulcsból (ez alapján rendezett) és az értékből.

SortedList

A SortedList egy rendezett lista, kulcsokat és értékeket tartalmaz, amelyhez a kulcsokon keresztül vagy indexelve férhetünk hozzá.

IList

Az IList egy nem generikus, objektumokból álló gyűjtemény (Collection), az egyes elemeit indexeléssel érhetjük el. Létezik generikus változata is, mégpedig a System.Collections.Generic.IList<>. A példányosítása a System.Collection.ArrayList osztály konstruktorával történik:

System.Collection.IList myIList = new ArrayList();

Az elemszámát az int típusú Count adattag adja meg, amit a System.Collection.ICollection-től örököl:

int lengthIList = myIList.Count;

Mivel bármilyen típusú elemet képes tárolni, ezért mondhatnám, hogy univerzális megoldás, de mégsem teszem, hisz vannak olyan esetek, amikor nem megfelelő. Pl. ha nagyon sok (többszázezer) elemmel dolgozunk és esetleg több ilyen adatszerkezetet is szeretnénk használni, akkor egy általunk megírt egyszerű tömböket használó adatszerkezet sokkal hatékonyabb lehet. Az sem kizárt, hogy memóriatakarékosabbat írunk.

Az IList fontosabb metódusai:

// Egy elemet ad a System.Collections.IList-hez.
// Paraméterek:
// value:
// Egy System.Object típusú elem, ezt adja hozzá a System.Collections.IList-hez.
// Visszatérési érték:
// Egy int típusú értéket ad vissza, ami a behelyezett elem helyét jelöli az IList-en belül..
int Add(object value);
 
// Kiüríti a System.Collections.IList-et.
void Clear();
 
// Meghatározza, hogy a System.Collections.IList tartalmazza-e a megadott elemet.
// Paraméterek:
// value:
// Egy System.Object típusú elem, ezt keresi a System.Collections.IList-ben.
// Visszatérési érték:
// true ha a value elemet megtalálta a System.Collections.IList-ben; különben false
bool Contains(object value);
 
// Meghatározza az adott elem indexét a System.Collections.IList-en belül.
// Paraméterek:
// value:
// Egy System.Object típusú elem, ezt keresi a System.Collections.IList-ben.
// Visszatérési érték:
// Az elem int típusú indexe, ha benne van a System.Collection.IList-ben; különben -1.
int IndexOf(object value);
 
// Beszúr egy elemet a System.Collections.IList-be egy adott indexű helyre.
// Paraméterek:
// value:
// Egy System.Object típusú elem, ezt szúrja be a System.Collections.IList-be.
// index:
// Egy int típusú index ahová a value elemet kell beszúrni.
void Insert(int index, object value);
 
// Eltávolítja az adott objektum első előfordulását a System.Collections.IList-ből.
// Paraméterek:
// value:
// Egy System.Object típusú elem, ezt távolítja el a System.Collections.IList-ből.
void Remove(object value);
 
// Eltávolítja a System.Collections.IList-ből a megadott elemet a megadott indexű helyről.
// Paraméterek:
// index:
// Egy int típusú index, ahonnan az elemet el kell távolítani.

void RemoveAt(int index);