Galileo Computing < openbook > Galileo Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

Inhaltsverzeichnis
Vorwort zur 6. Auflage
1 Allgemeine Einführung in .NET
2 Grundlagen der Sprache C#
3 Das Klassendesign
4 Vererbung, Polymorphie und Interfaces
5 Delegates und Ereignisse
6 Strukturen und Enumerationen
7 Fehlerbehandlung und Debugging
8 Auflistungsklassen (Collections)
9 Generics – Generische Datentypen
10 Weitere C#-Sprachfeatures
11 LINQ
12 Arbeiten mit Dateien und Streams
13 Binäre Serialisierung
14 XML
15 Multithreading und die Task Parallel Library (TPL)
16 Einige wichtige .NET-Klassen
17 Projektmanagement und Visual Studio 2012
18 Einführung in die WPF und XAML
19 WPF-Layout-Container
20 Fenster in der WPF
21 WPF-Steuerelemente
22 Elementbindungen
23 Konzepte von WPF
24 Datenbindung
25 Weitere Möglichkeiten der Datenbindung
26 Dependency Properties
27 Ereignisse in der WPF
28 WPF-Commands
29 Benutzerdefinierte Controls
30 2D-Grafik
31 ADO.NET – Verbindungsorientierte Objekte
32 ADO.NET – Das Command-Objekt
33 ADO.NET – Der SqlDataAdapter
34 ADO.NET – Daten im lokalen Speicher
35 ADO.NET – Aktualisieren der Datenbank
36 Stark typisierte DataSets
37 Einführung in das ADO.NET Entity Framework
38 Datenabfragen des Entity Data Models (EDM)
39 Entitätsaktualisierung und Zustandsverwaltung
40 Konflikte behandeln
41 Plain Old CLR Objects (POCOs)
Stichwort

Download:
- Beispiele, ca. 62,4 MB

Buch bestellen
Ihre Meinung?

Spacer
Visual C# 2012 von Andreas Kühnel
Das umfassende Handbuch
Buch: Visual C# 2012

Visual C# 2012
Rheinwerk Computing
1402 S., 6., aktualisierte und erweiterte Auflage 2013, geb., mit DVD
49,90 Euro, ISBN 978-3-8362-1997-6
Pfeil 9 Generics – Generische Datentypen
Pfeil 9.1 Problembeschreibung
Pfeil 9.2 Bereitstellen einer generischen Klasse
Pfeil 9.2.1 Mehrere generische Typparameter
Pfeil 9.2.2 Vorteile der Generics
Pfeil 9.3 Bedingungen (Constraints) festlegen
Pfeil 9.3.1 Constraints mit der »where«-Klausel
Pfeil 9.3.2 Typparameter auf Klassen oder Strukturen beschränken
Pfeil 9.3.3 Mehrere Constraints definieren
Pfeil 9.3.4 Der Konstruktor-Constraint »new()«
Pfeil 9.3.5 Das Schlüsselwort »default«
Pfeil 9.4 Generische Methoden
Pfeil 9.4.1 Methoden und Constraints
Pfeil 9.5 Generics und Vererbung
Pfeil 9.5.1 Virtuelle generische Methoden
Pfeil 9.6 Konvertierung von Generics
Pfeil 9.7 Generische Delegates
Pfeil 9.7.1 Generische Delegates und Constraints
Pfeil 9.7.2 Anpassung des Beispiels »GeometricObjects«
Pfeil 9.8 Nullable-Typen
Pfeil 9.8.1 Konvertierungen mit Nullable-Typen
Pfeil 9.9 Generische Collections
Pfeil 9.9.1 Die Interfaces der generischen Auflistungsklassen
Pfeil 9.9.2 Die generische Auflistungsklasse »List<T>«
Pfeil 9.9.3 Vergleiche mit Hilfe des Delegaten »Comparison<T>«
Pfeil 9.10 Kovarianz und Kontravarianz generischer Typen
Pfeil 9.10.1 Kovarianz mit Interfaces
Pfeil 9.10.2 Kontravarianz mit Interfaces
Pfeil 9.10.3 Zusammenfassung
Pfeil 9.10.4 Generische Delegaten mit varianten Typparametern

Galileo Computing - Zum Seitenanfang

9.10 Kovarianz und Kontravarianz generischer TypenZur nächsten Überschrift

In Abschnitt 5.1.6 haben wir uns bereits mit der Kovarianz und der Kontravarianz von Delegaten beschäftigt. Kovarianz und Kontravarianz wurden mit .NET 4.0 auch für generische Delegates und Interfaces eingeführt. Allerdings sind nicht alle generischen Delegates und Interfaces von Kovarianz und Kontravarianz betroffen, sondern nur einige wenige »Auserwählte«. Damit wurde es möglich, Code intuitiver zu schreiben.


Galileo Computing - Zum Seitenanfang

9.10.1 Kovarianz mit InterfacesZur nächsten ÜberschriftZur vorigen Überschrift

Lassen Sie uns zunächst ansehen, was unter der Kovarianz eines Interfaces zu verstehen ist. Um das zu zeigen, sind die elementaren Klassen unseres Projekts GeometricObjects hervorragend geeignet, die wir auch hier zur Veranschaulichung einsetzen wollen. Stellen Sie sich einfach vor, Sie würden eine Methode DoSomething schreiben, deren Parameter Sie Listen von Circle- oder Rectangle-Objekten übergeben wollen. Eine erste Idee könnte es sein, die Methode wie im folgenden Listing gezeigt zu überladen.

static void DoSomething(IEnumerable<Circle> param)
{
[...]
}

static void DoSomething(IEnumerable<Rectangle> param)
{
[...]
}

Listing 9.19 Methode mit Parameter vom Typ »IEnumerable<T>«

Der Zugriff auf diese Methoden könnte im Hauptprogramm folgendermaßen erfolgen:

static void Main(string[] args) {
List<Circle> objects1 = new List<Circle>();
objects1.Add(new Circle { Radius = 77 });
objects1.Add(new Circle { Radius = 23 });
List<Rectangle> objects2 = new List<Rectangle>();
objects2.Add(new Rectangle { Length = 120, Width = 10 });
objects2.Add(new Rectangle { Length = 80, Width = 20 });
DoSomething(objects1);
DoSomething(objects2);
Console.ReadLine();
}

Listing 9.20 Zugriff auf die Methoden aus Listing 9.19

Welche Operationen sich innerhalb der Methode DoSomething abspielen, ist bei unserer Betrachtung bedeutungslos. Beachten Sie hingegen, dass die Methoden einen Parameter vom Typ der Schnittstelle IEnumerable<T> definieren, der entweder für den Typ Circle oder den Typ Rectangle geprägt ist. Wäre es nicht intuitiver, die Überladung der Methode DoSomething durch eine allgemeingültige Version zu ersetzen, die die gemeinsame Basis GeometricObject angibt? Also ändern wir die Methode wie in Listing 9.21 gezeigt ab.

static void DoSomething(IEnumerable<GeometricObject> param)
{
[...]
}

Listing 9.21 Ersatz der Methoden aus Listing 9.19

Der Code wird in Visual Studio 2010 und 2012 einwandfrei kompiliert und fehlerfrei ausgeführt. Vielleicht steht Ihnen auch noch eine ältere Version von Visual Studio zur Verfügung, beispielsweise Visual Studio 2008. Versuchen Sie, den Code auch hier auszuführen, wird bereits das Kompilieren zu einem Fehler führen. Es funktioniert schlicht und ergreifend nicht.

Betrachten wir noch einmal die beiden Listings 9.19 und 9.21. Dass die Übergabe eines List<Circle>-Objekts an den Parameter der Methode DoSomething, der durch den Typ der Schnittstelle IEnumerable<Circle> beschrieben wird, keine Kopfschmerzen bereiten wird, geht aus der Beschreibung der Generics in diesem Kapitel bereits hervor.

Die Übergabe des List<Circle>-Objekts an den Parameter der Methode DoSomething aus Listing 9.21 entspricht im Grunde genommen der folgenden Zuweisungsoperation:

IEnumerable<GeometricObject> @object = new List<Circle>();

Die Zuweisung erscheint intuitiv, denn sie erinnert uns an die Polymorphie. Dennoch ist sie etwas Besonderes und wurde, wie schon erwähnt, erst mit .NET 4.0 eingeführt. Diese Zuweisungsoperation wird erst durch die kovariante Definition des generischen Typparameters möglich. Kovarianz wird durch die Angabe des Schlüsselwortes out vor dem generischen Typparameter sichergestellt. Nachfolgend sehen Sie die Definition des Interfaces IEnumerable<T>, wie es seit .NET 4.0 definiert ist.

public interface IEnumerable<out T>
{
IEnumerator<T> GetEnumerator();
}

Listing 9.22 Die Definition der kovarianten Schnittstelle »IEnumerable<T>«

Kovarianz bedeutet, dass auch ein abgeleiteter Typ anstelle des vom generischen Typparameter definierten verwendet werden kann. Das Schlüsselwort out gibt dabei an, dass der Typparameter nur als Typ einer Rückgabe verwendet werden kann (Ausgabe = Output). Dabei handelt es sich im Fall der IEnumerable<T>-Schnittstelle um die Rückgabe der Methode GetEnumerator.

Sie finden das komplette Beispiel auf der Buch-DVD unter ..\Kapitel 9\KovarianzSample.

Die Klassen Circle, Rectangle und GeometricObject sind in diesem Beispielprogramm auf das Wesentliche reduziert.


Galileo Computing - Zum Seitenanfang

9.10.2 Kontravarianz mit InterfacesZur nächsten ÜberschriftZur vorigen Überschrift

Während ein kovarianter Typparameter den Typ der Rückgabe beschreibt, dient ein kontravarianter Typparameter der Typangabe des Übergabearguments an eine Methode. Es ist daher auch naheliegend, dass kontravariante Typparameter durch das Schlüsselwort in ergänzt werden, um zu signalisieren, dass es sich dabei um Eingabetypen handelt. Zu den generischen Schnittstellen mit einem kontravarianten Typparameter gehört auch die Schnittstelle IComparer<T>.

public interface IComparer<in T>
{
int Compare(T x, T y);
}

Listing 9.23 Die Definition der kontravarianten Schnittstelle »IComparer<T>«

Erst die Definition als kontravarianter Typparameter ermöglicht uns eine Vergleichsklasse zu schreiben, deren generischer Typparameter auf GeometricObject festgelegt ist und die dennoch auch von allen Objekten genutzt werden kann, die von GeometricObject abgeleitet sind.

Das folgende Beispielprogramm nutzt das kontravariante Interface IComparer<T>, um eine Liste des Typs List<Circle> zu sortieren.

// Beispiel: ..\Kapitel 9\KontravarianzSample

class Program {
static void Main(string[] args) {
List<Circle> liste = new List<Circle>();
liste.Add(new Circle { Radius = 88 });
liste.Add(new Circle { Radius = 22 });
liste.Add(new Circle { Radius = 42 });
liste.Add(new Circle { Radius = 76 });
liste.Sort(new GeoComparer());

foreach (GeometricObject item in liste)
Console.WriteLine(item.GetArea());
Console.ReadLine();
}
}

class GeoComparer : IComparer<GeometricObject> {
public int Compare(GeometricObject x, GeometricObject y) {
return x.GetArea().CompareTo(y.GetArea());
}
}

Listing 9.24 Beispielprogramm zur Kontravarianz

Es braucht wahrscheinlich kaum noch erwähnt zu werden, dass auch dieses Beispielprogramm in Visual Studio 2008 (oder älter) zu einem Kompilierfehler führt.


Galileo Computing - Zum Seitenanfang

9.10.3 ZusammenfassungZur nächsten ÜberschriftZur vorigen Überschrift

Kovarianz wird durch das Schlüsselwort out vor dem generischen Typparameter festgelegt und führt dazu, dass der generische Typparameter nur zur Beschreibung eines Rückgabedatentyps verwendet werden kann. Kontravarianz hingegen definiert einen generischen Typparameter, der nur der Übergabe an eine Methode dient und mit dem Schlüsselwort in verziert wird.

Um den Sachverhalt noch einmal deutlich darzulegen, sollten Sie das folgende Listing der fiktiven Schnittstelle IFactory<T> betrachten.

// CreateInstance verursacht Kompilierfehler

public interface IFactory<in T> {
void DoSomething(T param);
T CreateInstance();
}

Listing 9.25 Fehlerverursachende Schnittstelle mit kontravariantem Typparameter

Der generische Typparameter ist mit in kontravariant definiert. Damit kann die Methode DoSomething korrekt bedient werden, während CreateInstance einen Kompilierfehler verursacht.

Definieren Sie nun einen kovarianten Typparameter (siehe Listing 9.26), wird CreateInstance kein Problem mehr verursachen. Jedoch ist DoSomething nun der Urheber eines Kompilierfehlers, weil die Methode einen kontravarianten Typparameter voraussetzt.

// DoSomething verursacht Kompilierfehler

public interface IFactory<out T> {
void DoSomething(T param);
T CreateInstance();
}

Listing 9.26 Fehlerverursachende Schnittstelle mit kovariantem Typparameter

Damit wird deutlich, dass es keine gleichzeitige Kovarianz und Kontravarianz für einen Parameter gibt. Es ist eine Entscheidung »Entweder-oder«. Es sollte auch klar sein, dass nicht alle Interfaces einen kovarianten oder kontravarianten Typparameter definieren müssen. In der .NET-Klassenbibliothek sind daher aktuell nur IEnumerable<T>, IEnumerator<T>, IQueryable<T> und IGrouping<T,K> kovariant, während zu den Schnittstellen mit kontravarianten generischen Typparametern IComparer<T> und IComparable<T> gerechnet werden.


Galileo Computing - Zum Seitenanfang

9.10.4 Generische Delegaten mit varianten TypparameternZur vorigen Überschrift

In .NET werden mit Action<> und Func<> generische Delegates bereitgestellt, die allgemeinen Anforderungen genügen. Einfach gesagt beschreibt ein Delegat vom Typ Action<> eine void-Methode, also eine Methode ohne Rückgabewert, Func<> hingegen eine Methode mit Rückgabewert.

Mit Action<> können wir Methoden beschreiben, die 1 bis 16 Parameter definieren, mit Func<> Methoden mit 0 bis maximal 16 Parametern. Sehen wir uns exemplarisch die Definition von jeweils einer Version dieser beiden Delegates an.

public delegate TResult Func<in T, out TResult>(T arg)

public delegate void Action<in T1, in T2>(T1 arg1, T2 arg2)

Hinsichtlich der beiden Schlüsselwörter in und out gilt dasselbe, was auch schon im Abschnitt zuvor erklärt worden ist: in gibt den Rahmen für die Typen der Eingabeparameter vor, out den Bereich der Typen für den Rückgabewert.

Das folgende Beispielprogramm zeigt den Einsatz dieser beiden Delegates. Das Programm selbst hat keinerlei Logik und soll nur dazu dienen, durch Austausch der Typen der generischen Typparameter die Verhaltensänderung zu untersuchen.

// Beispiel: ..\Kapitel 9\Kovariante_Kontravariante_Delegates

class GeometricObject { }
class Circle : GeometricObject { }
class Rectangle : GeometricObject { }

class Program
{
static void Main(string[] args)
{
Func<Circle, Circle> handler1 = DoSomething1;
Action<Rectangle> handler2 = DoSomething2;
}

static Circle DoSomething1(GeometricObject @object) {
return new Circle();
}

static void DoSomething2(GeometricObject @object) { }
}

Listing 9.27 Das Beispielprogramm »Kovariante_Kontravariante_Delegates«

In Abschnitt 5.1.6 habe ich Ihnen bereits die allgemeine Kovarianz und Kontravarianz von Delegaten vorgestellt.



Ihr Kommentar

Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen.

>> Zum Feedback-Formular
<< zurück
  Zum Katalog
Zum Katalog: Visual C# 2012

Visual C# 2012
Jetzt bestellen


 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Buchempfehlungen
Zum Katalog: Professionell entwickeln mit Visual C# 2012






 Professionell
 entwickeln mit
 Visual C# 2012


Zum Katalog: Windows Presentation Foundation






 Windows Presentation
 Foundation


Zum Katalog: Schrödinger programmiert C++






 Schrödinger
 programmiert C++


Zum Katalog: C++ Handbuch






 C++ Handbuch


Zum Katalog: C/C++






 C/C++


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo





Copyright © Rheinwerk Verlag GmbH 2013
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Rheinwerk Computing]

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de