Oftmals steht der Entwickler vor dem Problem, für eine Klasse (Methode) verschiedene Datentypen als Konstrukt zu realisieren. Methoden kann man zwar überschreiben und Klassen durch intelligente Interfaceauswahl generisch konstruieren (oder auch ganz einfach mit object), aber das ist u.U. mit Fleißarbeit und Mühen verbunden. Muss man wegen Datentypen wirklich so einen Aufstand treiben?
Nein - C# entwickelt sich weiter und vereinfacht so das Entwicklerleben. Das Zauberwort heisst Generic.
Heutzutage kann man natürlich auch schon solche Konstrukte entwickeln. Wir erinnern uns, dass jedes Objekt (Datentyp) in C# die Basis object implementiert hat. So ist auch klar, dass wir, wenn verschiedene Datentypen für ein und das selbe Konstrukt erforderlich sind, den Datentyp object verwenden. Betrachten wir hierzu einmal
das untere Listing.
public class MyClass { private object[] MyItems= new object[10];
public void MyMethod1(object data) { ... }
public object MyMethod2() { ... } } |
MyItems ist nun vom Datentyp object und kann dadurch alle Datentypen verwalten. Und hier entstehen schon mal die kleinen Probleme.
MyClass cls1 = new MyClass(); cls1.MyMethod1(new MyClass2()); MyClass2 cls2 = (MyClass2) cls1.MyMethod2(); |
Ist der Datentyp, in unserem Fall MyClass2 ein eigenes Konstrukt, so müssen wir ihn explizit durch eine Cast-Anweisung konvertieren.
MyClass2 cls2 = (MyClass2) cls1.MyMethod2(); |
Im nächsten Aufruf will man z.B. einen Datentyp int (Integer) dem Konstrukt zuordnen.
MyClass cls1 = new MyClass(); cls1.MyMethod1(10); int MyInt = (int) cls1.MyMethod2(); |
Übergibt man der Methode
MyMethod1 den Wertetypen 10 erfolgt eine implizite Konvertierung.
public object MyMethod2() { ... } |
Diese Methode liefert ein object zurück, also wird der int-Type geboxt. Um wieder einen Wertetypen zu erhalten muss hier mit
int MyInt = (int) cls1.MyMethod2(); |
ebenfalls wie bei cls2 explizit durch eine Cast-Anweisung konvertiert werden. Dieses boxen und unboxen kann in der Entwicklungsarbeit mit der Zeit sehr aufreibend sein.
Da freut man sich doch auf etwas einfacheres - Generic - ein neues Feature, dass in Zukunft im C# Compiler unterstütz werden soll. Schon wieder was neues wird so mancher Entwickler stöhnen. Ja, aber die Lernkuve ist sehr flach, da das Generic-Konstrukt semantisch sehr einfach ist. Sehen Sie selber!
public class MyClass<AnyType> { private AnyType[] MyItems;
public void MyMethod1(AnyType data) { ... }
public AnyType MyMethod2() { ... } } |
Der Aufruf des Konstrukts wird nun einfacher.
MyClass<int> cls1 = new MyClass<int>; cls1.MyMethod1(10); int MyInt = cls1.MyMethod2(); |
AnyType wird durch den Datentyp int (Integer) ersetzt. Ausserdem ersparen wir und das boxen und unboxen der Objekte. Das gleiche gilt auch bei eigene Klassenkonstrukte <MyOwnClass>. Ist ja toll - dann muss doch auch folgendes ausgeführt werden.
MyClass<MyOwnClass> cls1 = new MyClass<MyOwnClass>; cls1.MyMethod1(10); MyOwnClass cls2 = cls1.MyMethod2(); |
Natürlich nicht - da wir ja alle wissen, dass C# streng Typisiert ist. 10 vom Typ int hat natürlich nichts mit MyOwnClass gemeinsam und somit kann dieses Beispiel nicht funktionieren. Was aber wenn man nur eine vordefinierte Anzahl von Datentypen unterstützen möchte? Hier kann man dann folgendes Konstrukt erstellen.
public class MyClass<AnyType> where KeyType : IEnumerable, ValType : MyOwnClass { private AnyType[] MyItems;
public void MyMethod1(AnyType data) { ... }
public AnyType MyMethod2() { ... } } |
Da freut sich das C# Herz :_) shini