A System.Collection.Generic névtér (Generikusok)

Típusai:

  • Collection <T> -> Generikus gyűjtemény alapjai. - Compare<T> -> Két Generikus objektum egyenlőségét vizsgálja. - Dictionary<TKey, TValue> -> Kulcs/érték párok generikus gyűjteménye. - List<T> -> Elemek dinamikusan átméretezető listája. - Queue<T> -> "Elsőnek be, esőnek ki" FIFO lista generikus megvalósítása. - SortedDictionary<TKey, TValue> -> Rendezett kulcs/érték párok generikus megvalósítása. - Stack<T> -> "Utolsónak be, elsőnek ki" FIFO-lista generikus megvalósítása. - LinkedList<T> -> Kétirányú láncolt lista generikus megvalósítása. - ReadOnlyCollection<T> -> Írásvédett elemek csoportjának generikus megvalósítása. #### A List<T> típus vizsgálata:

A System.Collections.Generic.List<T> osztály megköveteli, hogy megadjunk neki egy olyan értéket, amely a List<T> által felhasznált elem típusát írja le. Tehát, ha három List<T> objektumot akarunk létrehozni annak érdekében, hogy megadjunk egészeket, valamint SportCar és Person objektumokat tároljunk, akkor a következőt írhatjuk:

	static void Main()
	{
		//List készítése egész számok tárolására
		List<int> myInts = new List<int>();

		//List készítése SportCar objektumok tárolására
		List<SportCar> myCars = new List<SportCar>();

		//List készítése Person típusú objektumok számára
		List<Person> myPerson = new List<Person>();
	}

Saját Generikus létrehozása:

A cél az, hogy létrehozzunk egy olyan swap metódus, amely bármely lehetséges adattípuson működik egyetlen paramétertípus használatával. Természetesen a bejövő paraméterek átadása referenciaként történik (C# ref kulcsszó).

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Genericethod
{
	class Program
	{
		//A metódus megcserél két elemet
		//a <T> típus paraméternek megfelelően
		static void Swap<T>(ref T a, ref T b)
		{
			Console.WriteLine("Te kuldtel a Swamp metodusnak {0}-(e)t",typeof(T));
			T temp;
			temp = a;
			a = b;
			b = temp;
		}
		static void Main(string[] args)
		{
			Console.WriteLine("Kezdodjon a moka a generikusokkal ;)\n\n");

			//két egész szám cseréje
			int a = 10, b = 90;
			Console.WriteLine("A csere elott: {0} {1}",a,b);
			Swap<int>(ref a, ref b);
			Console.WriteLine("A csere utan: {0} {1}\n", a, b);

			//Két sztring cseréje
			string s1 = "Elso", s2 = "Masodik";
			Console.WriteLine("A csere elott: {0} {1}", s1,s2);
			Swap<string>(ref s1, ref s2);
			Console.WriteLine("A csere utan: {0} {1}", s1, s2);

			Console.ReadKey();
		}
	}
}

Ugyan ez egy kicsit praktikusabban:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Genericethod
{
	class Program
	{
		static void Swap<T>(ref T a, ref T b)
		{
			Console.WriteLine("Te kuldel a Swap metodusnak {0}", typeof(T));
			Console.WriteLine("Csere elott: {0} {1}",a,b);
			T temp;
			temp = a;
			a = b;
			b = temp;
			Console.WriteLine("Csere utan: {0} {1}\n",a,b);
		}
		static void Main()
		{
			int a = 17, b = 3;
			Swap<int>(ref a, ref b);

			string s1 = "Ezt irtam elsonek", s2 = "Ezt meg masodiknak";
			Swap<string>(ref s1, ref s2);

			char c1 = 'a', c2 = 'b';
			Swap<char>(ref c1, ref c2);

			Console.ReadKey();
		}
	}
}

Ezek egy osztályobjektumba tartoznak, viszont természetesen megtehetjük, hogy külön osztályt hozunk létre a Swap metódusnak:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Genericethod
{
	class MyGenericMethod
	{
		public static void Swap<T>(ref T a, ref T b)
		{
			Console.WriteLine("Te kuldel a Swap metodusnak {0}", typeof(T));
			Console.WriteLine("Csere elott: {0} {1}", a, b);
			T temp;
			temp = a;
			a = b;
			b = temp;
			Console.WriteLine("Csere utan: {0} {1}\n", a, b);
		}
	}
	class Program
	{

		static void Main()
		{
			int a = 17, b = 3;
			MyGenericMethod.Swap<int>(ref a, ref b);

			string s1 = "Ezt irtam elsonek", s2 = "Ezt meg masodiknak";
			MyGenericMethod.Swap<string>(ref s1, ref s2);

			char c1 = 'a', c2 = 'b';
			MyGenericMethod.Swap<char>(ref c1, ref c2);

			Console.ReadKey();
		}
	}
}

Természetesen ezeknek nem kötelező. hogy statikusak legyenek. Egyszerűen létrehozunk egy pédányt és azz hívjuk meg. var peldany = new MyGenericMethod(); peldany.Swap<…>(ref …, ref …); Generikus Struktúrák és osztályok: Ezek segítségével megoldható például, hogy koordinátaként int-et, double-t, float-ot… is megadhassunk neki:

//Egész számokkal működik
Point<int> p = new Point<int>(10,15);

//double.el működik
Point<double> p = new Point<double>(3.466,6.3443);

…

Egy összetettebb példa:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Genericethod
{
	public struct Point<T>
	{
		T xPos;
		T yPos;

		//Generikus konstruktor
		public Point(T x, T y)
		{
			xPos = x;
			yPos = y;
		}

		//Generikus tulajdonságok
		public T X
		{
			get { return xPos; }
			set { xPos = value; }
		}
		public T Y
		{
			get { return yPos; }
			set { yPos = value; }
		}

		public override string ToString()
		{
			return string.Format("{0}, {1}", xPos, yPos);
		}

		//mezők visszaállítása a típusparaméter
		//alapértelmezett értékére (int-nek(értéktípus) az alapértelmezett                      
		//értéke 0, a stringnek(referenciaérték) null
		public void ResetPoint()
		{
			xPos = default(T);
			yPos = default(T);
		}
	}
	class MainClass
	{
		public static void Main()
		{
			//Egész számokkal működik
			Point<int> p = new Point<int>(10, 10);
			Console.WriteLine("p.ToString = {0}",p.ToString());
			p.ResetPoint(); // Itt lenullázzuk az értéket (mivel értéktípusnál ez az alapértelmezett)
			Console.WriteLine("p.ToString() = {0}",p.ToString());
			Console.ReadKey();

			//double számokkal működik
			Point<double> p2 = new Point<double>(5.4, 3.3);
			Console.WriteLine("\np2.ToString() = {0}",p2.ToString());
			p2.ResetPoint(); // Itt lenullázzuk az értéket (mivel értéktípusnál ez az alapértelmezett)
			Console.WriteLine("p2.ToString() = {0}", p2.ToString());

			Console.ReadKey();
		}
	}
}

Saját generikus gyűjtemény készítése:

using System;
using System.Collections;
using System.Collections.Generic;

namespace CustomGenericCollection
{
	public class Car
	{
		public string PetName;
		public int Speed;

		public Car(string name, int currentSpeed)
		{
			PetName = name;
			Speed = currentSpeed;
		}
		public Car() { }
	}

	public class SportsCar : Car
	{
		public SportsCar(string p, int s)
			: base(p, s) { }
	}

	public class MiniVan : Car
	{
		public MiniVan(string p, int s)
			: base(p, s) { }
	}

	public class CarCollection<T> : IEnumerable<T>
	{
		private List<T> arCars = new List<T>();

		public T GetCar(int pos)
		{ return arCars[pos]; }

		public void AddCar(T c)
		{ arCars.Add(c); }

		public void ClearCars()
		{ arCars.Clear(); }

		public int Count
		{ get { return arCars.Count; } }

		//Az IEnumerable<T> bővíti az IEnumerable interfészt.
		//ezért a GetEnumerator() mindkét verzióját meg kell valósítani.
		IEnumerator<T> IEnumerable<T>.GetEnumerator()
		{ return arCars.GetEnumerator(); }

		IEnumerator IEnumerable.GetEnumerator()
		{
			return arCars.GetEnumerator();
		}
	}

	class MainClass
	{
		public static void Main()
		{
			//objektumok létrehozása
			CarCollection<Car> myCars = new CarCollection<Car>();
			myCars.AddCar(new Car("Rusty", 20));
			myCars.AddCar(new Car("Zippy", 90));

			foreach (var c in myCars)
			{
				Console.WriteLine("PetName: {0}, Speed: {1}", c.PetName, c.Speed);
			}

			Console.ReadKey();
		}
	}
}

Generikusok

A generikusok szimpla használata

using System;
using System.Collections;
using System.Collections.Generic;

namespace gyakorlás
{
	class SwapClass
	{
		public void Swap<T>(ref T a, ref T b)
		{
			T tmp = a;
			a = b;
			b = tmp;
		}
	}

	class MainClass
	{
		public static void Main()
		{
			var swap = new SwapClass();

			int a = 10, b = 20;
			string s1 = "Hiba", s2 = "lesz";

			//swap.Swap<int>(ref a, ref b);
			Console.WriteLine("{0}, {1}", a, b);

			swap.Swap<string>(ref s1, ref s2);
			Console.WriteLine("{0}, {1}", s1, s2);

			Console.ReadKey();
		}
	}
}

mellett lehetőségünk van még rengeteg opcióra. A megszorításokon

using System;
using System.Collections;
using System.Collections.Generic;

namespace gyakorlás
{
	class SwapClass
	{
		public void Swap<T>(ref T a, ref T b) where T : struct
		{
			T tmp = a;
			a = b;
			b = tmp;
		}
	}

	class MainClass
	{
		public static void Main()
		{
			var swap = new SwapClass();

			int a = 10, b = 20;
			string s1 = "Hiba", s2 = "lesz";

			//swap.Swap<int>(ref a, ref b);
			Console.WriteLine("{0}, {1}", a, b);

			//Ez nem működik, mivel csak értéktípusokat fogadhat, ha a class
			//kulcsszó lenne a struct helyett, akkor lenne érvényes ez!
			//swap.Swap<string>(ref s1, ref s2);
			//Console.WriteLine("{0}, {1}", s1, s2);

			Console.ReadKey();
		}
	}
}

keresztül az előredefiniált generikus interfészekig... Mivel a generikusok bármilyen típust fogadhatnak, nem lehet operátorokat használni. Gondoljunk csak bele

public T Swap<T>(ref T a, ref T b)
{
	 return a + b;
}

Ez a példa nem fordul le! De mért nem? Hozzáadunk, valamilyen értéktípust (int, double, float…) például 5-öt meg 6-ot akkor mért nem tér vissza 11-el? Azért nem, mert referenciatípusnál nincs értelme operátor használatának. Mivel a rendszer gondol arra is, hogy akár stringet is hozzáadhatunk ezért nem fordul le! (Magyarul nincs értelne, hogy pl.: Pista + Sándor, vagy asd – dsa…) #### Generikus ősosztályok

Ha generikus osztályból származtatunk, akkor öröklésnél meg kell határoznunk, hogy milyen típust fogunk visszaadni a generikusnak.

public class MyList<T>
{
	List<T> listOfData = new List<T>();
}
//a konkrét típusoknak meg kell határoznia a típus
//paramétert, ha generikus osztály leszármazottjai
public class myStrigList : MyList<string>
{

}

Ugyan ez a helyzet felüldefiniálásoknál.

public class MyList<T>
{
	 List<T> listOfData = new List<T>();
	 public virtual void PrintData(T data) { }
}
//a konkrét típusoknak meg kell határoznia a típus
//paramétert, ha generikus osztály leszármazottjai
public class myStrigList : MyList<string>
{
	 public override void PrintData(string data)
	 {
	 }
}

Ezt viszont meg tudja helyettünk csinálni a visual studio! Leírjuk hogy: public override void és ekkor megjelenik az intellisense abból kiválasztjuk a kérdéses metódust, és autómatikusan felüldefiniálja nekünk a régit. #### Generikus interfészek

Már volt szó róla, hogy operátorokat nem használhatunk generikusoknál bizonyos okokból. Ezt ki lehet küszöbölni a megszorítások és interfészek használatával:

using System;
using System.Collections.Generic;
using System.Text;

namespace GenericInterface
{
  #region A generic interface
  public interface IBinaryOperations<T> where T : struct
  {
	T Add(T arg1, T arg2);
	T Subtract(T arg1, T arg2);
	T Multiply(T arg1, T arg2);
	T Divide(T arg1, T arg2);
  }
  #endregion

  #region Implementation of generic interface.
  public class BasicMath : IBinaryOperations<float>
  {
	public float Add(float arg1, float arg2)
	{ return arg1 + arg2; }

	public float Subtract(float arg1, float arg2)
	{ return arg1 - arg2; }

	public float Multiply(float arg1, float arg2)
	{ return arg1 * arg2; }

	public float Divide(float arg1, float arg2)
	{ return arg1 / arg2; }
  }
  #endregion

  class Program
  {
	static void Main(string[] args)
	{
	  Console.WriteLine("***** Generic Interfaces *****\n");
	  BasicMath m = new BasicMath();
	  Console.WriteLine("1.98 + 1.3 = {0}", m.Add(1.98F, 1.3F));
	  Console.ReadLine();
	}
  }
}
Harder

Harder

Profil