Rheinwerk Computing < openbook > Rheinwerk 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

Jetzt 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 10 Weitere C#-Sprachfeatures
Pfeil 10.1 Implizit typisierte Variablen
Pfeil 10.2 Anonyme Typen
Pfeil 10.3 Lambda-Ausdrücke
Pfeil 10.3.1 Projektion und Prädikat
Pfeil 10.4 Erweiterungsmethoden
Pfeil 10.5 Partielle Methoden
Pfeil 10.5.1 Wo partielle Methoden eingesetzt werden
Pfeil 10.6 Operatorüberladung
Pfeil 10.6.1 Einführung
Pfeil 10.6.2 Die Syntax der Operatorüberladung
Pfeil 10.6.3 Die Operatorüberladungen im Projekt »GeometricObjectsSolution«
Pfeil 10.6.4 Die Operatoren »true« und »false« überladen
Pfeil 10.6.5 Benutzerdefinierte Konvertierungen
Pfeil 10.7 Indexer
Pfeil 10.7.1 Überladen von Indexern
Pfeil 10.7.2 Parameterbehaftete Eigenschaften
Pfeil 10.8 Attribute
Pfeil 10.8.1 Das »Flags«-Attribut
Pfeil 10.8.2 Benutzerdefinierte Attribute
Pfeil 10.8.3 Attribute auswerten
Pfeil 10.8.4 Festlegen der Assembly-Eigenschaften in »Assembly-Info.cs«
Pfeil 10.9 Dynamisches Binden
Pfeil 10.9.1 Eine kurze Analyse
Pfeil 10.9.2 Dynamische Objekte
Pfeil 10.10 Unsicherer (unsafe) Programmcode – Zeigertechnik in C#
Pfeil 10.10.1 Einführung
Pfeil 10.10.2 Das Schlüsselwort »unsafe«
Pfeil 10.10.3 Die Deklaration von Zeigern
Pfeil 10.10.4 Die »fixed«-Anweisung
Pfeil 10.10.5 Zeigerarithmetik
Pfeil 10.10.6 Der Operator »->«

Rheinwerk Computing - Zum Seitenanfang

10.7 IndexerZur nächsten Überschrift

In Kapitel 2 haben Sie gelernt, mit Arrays zu arbeiten. Sie wissen, wie Sie ein Array deklarieren und auf die einzelnen Elemente zugreifen können, z. B.:

int[] arr = new int[10];
arr[3] = 125;

Mit C# können Sie Klassen und Strukturen so definieren, dass deren Objekte wie ein Array indiziert werden können. Indizierbare Objekte sind in der Regel Objekte, die als Container für andere Objekte dienen – vergleichbar einem Array. Das .NET Framework stellt uns mit den Collections eine Vielzahl solcher Klassen zur Verfügung.

Stellen Sie sich vor, Sie würden die Klasse Team entwickeln. Eine Mannschaft setzt sich aus vielen Einzelspielern zusammen, die innerhalb der Klasse in einem Array vom Typ Player verwaltet werden. Wenn Sie die Klasse Team mit

Team Wacker = new Team();

instanziieren, wäre es doch zweckdienlich, sich von einem bestimmten Spieler mit der Anweisung

string name = Wacker[2].Name;

den Zunamen zu besorgen. Genau das leistet ein Indexer. Wir übergeben dem Objekt einen Index in eckigen Klammern, der ausgewertet wird und die Referenz auf ein Player-Objekt zurückliefert. Darauf können wir mit dem Punktoperator den Zunamen des gewünschten Spielers ermitteln, vorausgesetzt, diese Eigenschaft ist in der Klasse Player implementiert.

Ein Indexer ist prinzipiell eine Eigenschaft, die mit this bezeichnet wird und in eckigen Klammern den Typ des Index definiert. Weil sich this immer auf ein konkretes Objekt bezieht, können Indexer niemals static deklariert werden.

<Modifikatoren> <Datentyp> this[<Parameterliste>]

Als Modifizierer sind neben den Zugriffsmodifikatoren auch new, virtual, sealed, override und abstract zulässig. Wenn wir uns in Erinnerung rufen, was wir im vorhergehenden Abschnitt über Operatorüberladung gelernt haben, kommt man auch nicht an der Aussage vorbei, Indexer als eine Überladung des []-Operators zu betrachten.

Wenn eine Klasse einen Indexer definiert, darf diese Klasse keine Item-Methode haben, weil interessanterweise ein Indexer als Item-Methode interpretiert wird.

Mit diesem Wissen ausgestattet, sollten wir uns nun die Implementierung der Klasse Mannschaft ansehen.

// Beispiel: ..\Kapitel 10\IndexerSample
class Program {
static void Main(string[] args) {
Team Wacker = new Team();
// Spieler der Mannschaft hinzufügen
Wacker[0] = new Player { Name = "Fischer", Age = 23 };
Wacker[1] = new Player { Name = "Müller", Age = 19 };
Wacker[2] = new Player { Name = "Mamic", Age = 33 };
Wacker[3] = new Player { Name = "Meier", Age = 31 };
// Spielerliste ausgeben
for (int index = 0; index < 25; index++) {
if (Wacker[index] != null)
Console.WriteLine("Name: {0,-10}Alter: {1}",
Wacker[index].Name, Wacker[index].Age);
}
Console.ReadLine();
}
}
// Mannschaft
public class Team {
private Player[] team = new Player[25];
// Indexer
public Player this[int index] {
get { return team[index]; }
set {
// prüfen, ob der Index schon besetzt ist
if (team[index] == null)
team[index] = value;
else
// nächsten freien Index suchen
for (int i = 0; i < 25; i++)
if (team[i] == null) {
team[i] = value;
return;
}
}
}
}
// Spieler
public class Player {
public string Name { get; set;}
public int Age { get; set; }
}

Listing 10.34 Beispielprogramm zum Indexer

Jede Instanz der Klasse Team verhält sich wie ein Array. Dafür verantwortlich ist der Indexer, der über das Schlüsselwort this deklariert wird und einen Integer entgegennimmt. Der Indexer ist vom Typ Player. Der lesende und schreibende Zugriff auf ein Element erfolgt unter Angabe seines Index, also beispielsweise:

Wacker[6];

Die interne Struktur eines Indexers gleicht der einer Eigenschaftsmethode: Sie enthält einen get- und einen set-Accessor. get wird aufgerufen, wenn durch die Übergabe des int-Parameters Letzterer als Index der Player-Arrays ausgewertet wird und den entsprechenden Spieler aus dem privaten Array zurückgibt. Die Zuweisung eines weiteren Spielers hat den Aufruf des set-Zweiges zur Folge. Dabei wird überprüft, ob der angegebene Index noch frei oder bereits belegt ist. Im letzteren Fall wird der erste freie Index gesucht.


Rheinwerk Computing - Zum Seitenanfang

10.7.1 Überladen von IndexernZur nächsten ÜberschriftZur vorigen Überschrift

In einem herkömmlichen Array erfolgt der Zugriff auf ein Element grundsätzlich über den Index vom Typ int, aber Indexer lassen auch andere Datentypen zu. In vielen Situationen ist es sinnvoll, anstelle des Index eine Zeichenfolge anzugeben, mit der ein Element identifiziert wird. Meistens handelt es sich dabei um den Namen des Elements. Sind mehrere unterschiedliche Zugriffe wünschenswert, können Indexer nach den bekannten Regeln hinsichtlich Anzahl und Typ der Parameter überladen werden.

Das folgende Beispiel zeigt eine Indexerüberladung. Dazu benutzen wir das Beispiel aus dem vorherigen Abschnitt und ergänzen die Klasse Team um einen weiteren Indexer in der Weise, dass wir auch über den Namen des Spielers auf das zugehörige Objekt zugreifen können, also zum Beispiel mit

Player spieler = Wacker["Fischer"];

Angemerkt sei dabei, dass das Beispiel nur wunschgemäß funktioniert, solange die Namen eindeutig sind. Sollten mehrere Spieler gleichen Namens in der Liste zu finden sein, müssten weitere Kriterien zur eindeutigen Objektbestimmung herangezogen werden. Das soll aber nicht das Thema an dieser Stelle sein.

// Beispiel: ..\Kapitel 10\IndexerUeberladungSample
class Program {
static void Main(string[] args) {
Team Wacker = new Team();
// Spieler der Mannschaft hinzufügen
Wacker[0] = new Player { Name = "Fischer", Age = 23 };
Wacker[1] = new Player { Name = "Müller", Age = 19 };
Wacker[2] = new Player { Name = "Mamic", Age = 33 };
Wacker[3] = new Player { Name = "Meier", Age = 31 };
// Spieler suchen
Console.Write("Spieler suchen: ... ");
string spieler = Console.ReadLine();
if (Wacker[spieler] != null){
Console.WriteLine("{0} gefunden, Alter = {1}",
Wacker[spieler].Name, Wacker[spieler].Age);
Console.WriteLine(Wacker[spieler].Age);
}
else
Console.WriteLine("Der Spieler gehört nicht zum Team.");
Console.ReadLine();
}
}
// Mannschaft
public class Team {
private Player[] team = new Player[25];
// Indexer
public Player this[int index] {
[...]
}
public Player this[string name] {
get {
for (int index = 0; index < 25; index++) {
if (team[index] != null && team[index].Name == name)
return team[index];
}
return null;
}
}
}

Listing 10.35 Beispiel mit Indexerüberladung

Die Überladung des Indexers mit einem string enthält nur den get-Accessor, da die Zuweisung eines neuen Player-Objekts nur anhand seines Namens in diesem Beispiel unsinnig wäre. Im get-Accessor wird eine Schleife über alle Indizes durchlaufen. Jeder Index wird dahingehend geprüft, ob er einen von null abweichenden Inhalt hat. Ist der Inhalt nicht null und verbirgt sich hinter dem Index auch das Player-Objekt mit dem gesuchten Namen, wird das Objekt an den Aufrufer zurückgegeben. Diese Operation wird durch

if (team[index] != null &&  team[index].Name == name)
return team[index];

beschrieben. Sollte sich ein Spieler mit dem gesuchten Namen nicht in der Mannschaft befinden, ist der Rückgabewert null.


Rheinwerk Computing - Zum Seitenanfang

10.7.2 Parameterbehaftete EigenschaftenZur vorigen Überschrift

Eigenschaften sind per Definition parameterlos. Mit anderen Worten: Sie können einen Eigenschaftswert nicht in Abhängigkeit von einer oder mehreren Nebenbedingungen setzen. Aber es geht doch! Tatsächlich ließe sich die folgende Wertzuweisung an eine Eigenschaft programmieren:

@object.MyProperty[2] = 10;

In der fiktiven Eigenschaft MyProperty lautet die Randbedingung »2«. Unter dieser Prämisse soll der Eigenschaft die Zahl 10 zugewiesen werden. Der Code ähnelt ohne Zweifel einem Array und lässt sich auch so interpretieren: Es handelt sich um eine indizierte Sammlung gleichnamiger Eigenschaftselemente. Daher führt der Weg zur Lösung auch in diesem Fall über Indexer. Wir sollten uns das Verfahren an einem konkreten Beispiel ansehen und stellen uns daher vor, wir würden eine Klasse Table codieren mit einer Eigenschaft Cell. Wenn table eine Instanz der Klasse Table ist, soll mit

table.Cell[2,1] = 97;

einer bestimmten Zelle der Tabelle ein Wert zugewiesen werden.

Ein Indexer setzt ein Objekt voraus, denn wie wir wissen, überladen wir den []-Operator in this, dem aktuellen Objekt also. Daraus kann gefolgert werden, dass wir zusätzlich zur Klasse Table eine zweite Klasse definieren müssen, die ihrerseits die Eigenschaft beschreibt. Im Folgenden soll der Name dieser Klasse Content lauten.

Wir könnten nun beide Klassen mit

public class Table { [...] }
public class Content { [...] }

festlegen.

Ein Objekt vom Typ Content soll einem Benutzer als schreibgeschützte Eigenschaft eines Table-Objekts angeboten werden. Wir ergänzen deshalb die Klassendefinition Table um ein Feld, das die Referenz auf ein Content-Objekt zurückliefert, und veröffentlichen diese über den get-Zweig der Eigenschaft Cell:

class Table {
private Content _Cell = new Content();
public Content Cell {
get { return _Cell; }
}
}

Die Klasse Table können wir bereits als fertig betrachten. Widmen wir uns nun der Klasse Content und dem in dieser Klasse programmierten Indexer. Da wir die Absicht haben, als Randbedingung der Eigenschaft Cell den Index der Zeile und Spalte der von uns angesprochenen Zelle mitzuteilen, sieht ein erster Entwurf des Indexers wie folgt aus:

class Content {
public int this[int row, int column] {
get { return arr[row, column]; }
set { arr[row, column] = value; }
}
}

Die Tabelle soll durch ein zweidimensionales Array dargestellt werden. Daher müssen wir sicherstellen, dass bei Übergabe der Bedingung nicht die Arraygrenzen überschritten werden – sowohl im set- als auch im get-Zweig. Eine private Methode in Content bietet sich zu diesem Zweck an:

private void CheckIndex(int row, int column) {
if (row < arr.GetLength(0) && column < arr.GetLength(1))
return;
else
throw new IndexOutOfRangeException("Ungültiger Index");
}

Die Variable arr sei die Referenz auf das Array, das die Tabellendaten repräsentiert. CheckIndex wird im set- und get-Zweig der Eigenschaft Cell aufgerufen.

Damit sind wir nahezu fertig mit dem Beispielprogramm. Was noch fehlt ist die Datenquelle, also das Array, und entsprechender Code zum Testen. Das Array können wir zu Testzwecken in der Klasse Content hinterlegen, das soll an dieser Stelle genügen.

Den gesamten Code zur Implementierung der parametrisierten Eigenschaft fassen wir an dieser Stelle endgültig zusammen.

// Beispiel: ..\Kapitel 10\ParametrisierteProperty
class Program {
static void Main(string[] args) {
Table table = new Table();
PrintArray(table);
table.Cell[2,1] = 97;
Console.WriteLine();
PrintArray(table);
Console.ReadLine();
}
// Ausgabe des Arrays im Tabellenformat
static void PrintArray(Table tbl) {
for(int row = 0; row < 4; row++) {
for(int col = 0; col < 3; col++)
Console.Write("{0,-3}",tbl.Cell[row, col]);
Console.WriteLine();
}
}
}
// Klasse Table
class Table {
private Content _Cell = new Content();
public Content Cell
{
get { return _Cell; }
}
}
// Klasse Content
class Content {
private int[,] arr = { {1,2,3}, {4,5,6}, {7,8,9}, {10,11,12} };
// Indexer
public int this[int row, int column]
{
get {
CheckIndex(row, column);
return arr[row, column];
}
set {
CheckIndex(row, column);
arr[row, column] = value;
}
}
// Prüfen der Arraygrenzen
private void CheckIndex(int row, int column) {
if (row < arr.GetLength(0) && column < arr.GetLength(1))
return;
else
throw new IndexOutOfRangeException("Ungültiger Index");
}
}

Listing 10.36 Definition einer parameterbehafteten Eigenschaft



Ihre Meinung

Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.

<< zurück
  Zum Rheinwerk-Shop
Zum Rheinwerk-Shop: Visual C# 2012

Visual C# 2012
Jetzt Buch bestellen


 Ihre Meinung?
Wie hat Ihnen das Openbook gefallen?
Ihre Meinung

 Buchempfehlungen
Zum Rheinwerk-Shop: Professionell entwickeln mit Visual C# 2012






 Professionell
 entwickeln mit
 Visual C# 2012


Zum Rheinwerk-Shop: Windows Presentation Foundation






 Windows Presentation
 Foundation


Zum Rheinwerk-Shop: Schrödinger programmiert C++






 Schrödinger
 programmiert C++


Zum Rheinwerk-Shop: C++ Handbuch






 C++ Handbuch


Zum Rheinwerk-Shop: C/C++






 C/C++


 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und der Schweiz
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.


Nutzungsbestimmungen | Datenschutz | Impressum

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

Cookie-Einstellungen ändern