Szablony

Szablony (ang. Generics) pozwalają na parametryzację klas, struktur, delagacji lub metod, w zależności od tego, jaki typ danych mają przechowywać lub przetwarzać. Przykładowo:


public class Stos<T>
{
	T[ ] elementy;
	public void Push( T element) {...}
	public T Pop( ) {...}
}
...
Stos<int>  stos = new Stos<int>( );    // utworzenie obiektu stosu przechowującego wartości int.
stos.Push(3);                          // włożenie nowej wartości na stos
int x = stos.Pop( );                   // zdjęcie liczby ze stosu (nie wymaga rzutowania)

Wyrażenie Stos<int> jest typem gotowym do użycia - wewnątrz deklaracji klasy/szablonu Stos wszystkie wystąpienia parametru T są zamieniane na int i dopiero wtedy powstaje typ Stos<int>.

Oczywiście metody klasy Stos<int> (czyli Pop i Push) operują na klasie int. Eliminuje to konieczność rzutowania wartości zdejmowanej ze stosu (tym bardziej, że próba włożenia na taki stos wartości innego typu niż int, spowodowała by błąd już podczas kompilacji).

Deklaracja szablonu może zawierać dowolną ilość parametrów (np. class Łącznik{...} ).

where : słowo kluczowe pozwalające nadawać ograniczenia na typ przekazywany jako argument szablonu. Dzięki temu możemy zapewnić silniejszą kontrolę typów podczas kompilacji oraz zminimalizować potrzebę rzutowania. Przykładowo:

public class Słownik<Klucz, Wartość > where Klucz: IComparable
{
   public void Dodaj( Klucz k, Wartość w)
   {
      if( k.CompareTo(x) < 0 ) {...}	 // Nie jest wymagane rzutowanie
   }	                                 // k do IComparable.
}

Każdy typ, który ma wystąpić w miejscu parametru danego szablonu, musi w całości wypełniać wszelkie ograniczenia nałożone na dany parametr (w przeciwnym razie wystąpi błąd kompilacji).

default : pozwala pobrać domyślną wartość danego typu. Dzięki temu możemy zainicjować wewnątrz szablonu w jednolity sposób zarówno zmienne typów bezpośrednich ( value type ) jak też referencyjnych (reference type).
Np. class Wzorzec<T > { T t = default( T ); ... }

Szablony metod

Czasami parametry nie są potrzebne dla całej klasy szablonu, ale tylko dla pewnych szczególnych metod. Zdarza się to często, gdy metoda operuje na parametrze, który jest szablonem. Np.

	void PushMultiple<T>( Stos<T> stos, params T[] wartości) {
		foreach( T wartość  in wartości) stos.Push( wartość );
	}

	Stos<int> stos = new Stos<int>();
	PushMultiple<int>(stos, 1, 2, 3 );	// <-- wywołanie szablonu metody.

W wielu wypadkach kompilator sam jest w stanie odkryć jaki typ powinien być obsłużony przez konkretne wywołanie szablonu metody. I tak w przykładzie powyżej można by metodę PushMultiple wywołać jako PushMultiple(stos, 1, 2, 3); (kompilator sam odkryje, że chodzi o PushMultiple<int> ).


prev | Strona Główna | next

Copyright © 2006 Daniel Dusiński
Wszelkie prawa zastrzeżone