Microsoft Visual C# 2008

Werbung
Microsoft Visual C#
2008
Schri tt für Schri tt
Microsoft Visual C# 2008 – Schritt für Schritt
Mirco De Roni, 2010
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
Inhaltsverzeichnis
1
Willkommen bei C#............................................................................................................ 5
Ihr erstes C#-Programm schreiben ...................................................................................... 5
Namespaces und Assemblys............................................................................................... 5
Eine grafische Anwendung erstellen .................................................................................... 6
2 Mit Variablen, Operatoren und Ausdrücke arbeiten ........................................................ 7
Anweisungen verstehen ...................................................................................................... 7
Bezeichner verwenden ........................................................................................................ 7
Schlüsselwörter identifizieren .............................................................................................. 7
Variablen verwenden ........................................................................................................... 8
Mit primitiven Datentypen arbeiten ...................................................................................... 8
Arithmetische Operatoren verwenden.................................................................................. 9
Variablen inkrementieren und dekrementieren .................................................................. 10
Implizit typisierte lokale Variablen deklarieren ................................................................... 11
3 Methoden schreiben und Gültigkeitsbereiche anwenden ............................................ 12
Methoden deklarieren ........................................................................................................ 12
Methoden aufrufen ............................................................................................................ 12
Gültigkeitsbereiche anwenden ........................................................................................... 13
4 Entscheidungsanweisungen verwenden ....................................................................... 15
Boolesche Variablen deklarieren ....................................................................................... 15
Boolesche Operatoren verwenden .................................................................................... 15
Entscheidungen mit if-Anweisungen treffen .................................................................... 16
switch-Anweisungen verwenden ........................................................................................ 17
5 Verbundzuweisungen und Schleifen verwenden .......................................................... 19
Verbundzuweisungsoperatoren verwenden ....................................................................... 19
Schleifen mit while-Anweisungen schreiben.................................................................... 19
Schleifen mit for-Anweisungen schreiben ........................................................................ 19
Schleifen mit do-Anweisungen schreiben .......................................................................... 20
6 Fehler und Ausnahmen behandeln ................................................................................ 21
Code probieren und Ausnahmen abfangen ....................................................................... 21
Ganzzahlarithmetik mit checked und unchecked ........................................................... 22
Ausnahmen auslösen ........................................................................................................ 23
Einen finally-Block verwenden ..................................................................................... 23
7 Klassen und Objekte erstellen und verwalten ............................................................... 24
Was ist Klassifizierung? ..................................................................................................... 24
Was ist Kapselung? ........................................................................................................... 24
Eine Klasse definieren und verwenden .............................................................................. 24
Den Zugriff kontrollieren .................................................................................................... 25
Mit Konstruktoren arbeiten ................................................................................................. 25
Statische Methoden und Daten verstehen ......................................................................... 27
8 Werte und Verweise verstehen ....................................................................................... 30
Werttypvariablen und Klassen kopieren............................................................................. 30
NULL-Werte und Typen, die NULL-Werte zulassen........................................................... 30
Parameter mit ref und out übergeben ................................................................................ 31
Wie der Computerspeicher organisiert ist .......................................................................... 32
Die Klasse System.Object ................................................................................................. 32
Daten sicher konvertieren .................................................................................................. 32
9 Werttypen mit Enumerationen und Strukturen erstellen .............................................. 33
Mit Enumerationen arbeiten ............................................................................................... 33
Mit Strukturen arbeiten ...................................................................................................... 33
10 Arrays und Auflistungen verwenden ............................................................................. 35
Was ist ein Array? ............................................................................................................. 35
Was sind Auflistungsklassen? ........................................................................................... 36
11 Parameterarrays verstehen ............................................................................................ 41
Mirco De Roni
-2-
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
Arrayargumente verwenden .............................................................................................. 41
12 Vererbung richtig einsetzen............................................................................................ 42
Was ist Vererbung? ........................................................................................................... 42
Vererbung einsetzen ......................................................................................................... 42
13 Schnittstellen erstellen und abstrakte Klassen deklarieren ......................................... 45
Schnittstellen verstehen..................................................................................................... 45
Schnittstellensyntax ...................................................................................................... 45
Schnittstelleneinschränkungen...................................................................................... 45
Eine Schnittstelle implementieren ................................................................................. 45
Auf eine Klasse über ihre Schnittstelle verweisen ......................................................... 47
Mit mehreren Schnittstellen arbeiten ............................................................................. 47
Abstrakte Klassen.............................................................................................................. 47
Versiegelte Klassen ........................................................................................................... 49
14 Garbage Collection und Ressourcenverwaltung einsetzen ......................................... 50
Der Lebenszyklus von Objekten ........................................................................................ 50
Destruktoren erstellen ................................................................................................... 50
Warum wird der Garbage Collector verwendet? ............................................................ 51
Wie funktioniert der Garbage Collector?........................................................................ 51
Ressourcenverwaltung ...................................................................................................... 52
Freigabemethoden ........................................................................................................ 52
Ausnahmesichere Freigabe von Ressourcen ................................................................ 52
Die using-Anweisung .................................................................................................... 53
15 Eigenschaften implementieren, um auf Attribute zuzugreifen ..................................... 54
Was sind Eigenschaften? .................................................................................................. 54
Eigenschaften verwenden ............................................................................................. 55
Schreibgeschützte Eigenschaften ................................................................................. 55
Lesegeschützte Eigenschaften ..................................................................................... 55
Zugriffsmodifizierer bei Eigenschaften .......................................................................... 55
Einschränkungen von Eigenschaften verstehen ................................................................ 56
Schnittstelleneigenschaften deklarieren............................................................................. 56
16 Delegaten und Ereignisse ............................................................................................... 57
Delegaten deklarieren und verwenden .............................................................................. 57
Benachrichtigungen mit Ereignissen realisieren ................................................................ 58
Ein Ereignis deklarieren ................................................................................................ 58
Ein Ereignis abonnieren ................................................................................................ 58
Das Abonnement eines Ereignisses kündigen .............................................................. 58
Ein Ereignis auslösen.................................................................................................... 58
17 Einführung in Generics ................................................................................................... 60
Eine generische Klasse erstellen ....................................................................................... 60
Die Theorie der binären Bäume .................................................................................... 60
Eine Binärbaum-Klasse mit Generics erstellen.............................................................. 60
18 Speicherinterne Daten mit Abfrageausdrücken abrufen .............................................. 62
Was ist LINQ? ................................................................................................................... 62
LINQ in einer C#-Anwendung einsetzen ............................................................................ 62
Daten auswählen .......................................................................................................... 64
Daten filtern .................................................................................................................. 64
Daten sortieren, gruppieren und zusammenfassen ....................................................... 64
Daten verknüpfen.......................................................................................................... 65
19 Überladen von Operatoren ............................................................................................. 66
Operatoren verstehen ........................................................................................................ 66
Operatoreneinschränkungen ......................................................................................... 66
Überladene Operatoren ................................................................................................ 66
Verbundzuweisungen verstehen........................................................................................ 67
20 Einführung in Windows Presentation Foundation ........................................................ 68
Eine WPF-Anwendung erstellen ........................................................................................ 68
Mirco De Roni
-3-
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
21
22
23
24
Steuerelemente in das Formular aufnehmen ..................................................................... 69
Ereignisse in einem WPF-Formular behandeln .................................................................. 69
Mit Menüs und Dialogfeldern arbeiten ........................................................................... 70
Richtlinien für Menüs ......................................................................................................... 70
Menüs und Menüereignisse ............................................................................................... 70
Kontextmenüs ................................................................................................................... 71
Windows-Standarddialogfelder .......................................................................................... 71
Die Klasse SaveFileDialog verwenden .......................................................................... 71
Eine Datenbank verwenden ............................................................................................ 72
Eine Datenbank mit ADO.NET abfragen ............................................................................ 72
Die Northwind-Datenbank ............................................................................................. 72
Bestellinformationen mit ADO.NET abfragen ................................................................ 72
Eine Datenbank mit DLINQ abfragen................................................................................. 74
Eine Entitätsklasse definieren ....................................................................................... 74
Bestellinformationen mit einer DLINQ-Abfrage abrufen ................................................. 75
Einen Webdienst erstellen und verwenden ................................................................... 77
Was ist ein Webdienst? ..................................................................................................... 77
Die Rolle von SOAP ...................................................................................................... 77
Was ist die Web Services Description Language? ........................................................ 77
Einen Webdienst erstellen ................................................................................................. 77
Quellenverzeichnis .......................................................................................................... 79
Mirco De Roni
-4-
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
1
Willkommen bei C#
Microsoft Visual C# ist Microsofts leistungsfähigste komponentenorientierte Programmiersprache. C#
spielt in der Architektur des Microsoft .NET Frameworks eine entscheidende Rolle und man hat
Parallelen gezogen zu der Rolle, die die Programmiersprache C in der Entwicklung von Unix
eingenommen hat.
Ihr erstes C#-Programm schreiben
Die Datei Program.cs definiert eine Klasse Program, die eine Methode Main enthält. Alle Methoden
müssen innerhalb einer Klasse definiert werden. Die Methode Main ist eine spezielle Methode und stellt
den Programmeintrittspunkt dar.
static void Main(string[] args)
{
System.Console.WriteLine("Hello World");
}
Wichtig
Die Programmiersprache C# berücksichtigt die Gross-/ Kleinschreibung. Deshalb müssen Sie Main mit
einem grossen M schreiben.
IntelliSense-Symbole:
Symbol
Bedeutung
Methode
Eigenschaft
Klasse
Struktur
Enumeration
Schnittstelle
Delegat
Erweiterungsmethode
Hinweis
Häufig enthalten Codezeilen zwei Schrägstriche und einen darauf folgenden Text. Dabei handelt es sich
um Kommentare. Der Compiler ignoriert sie, aber sie sind sehr nützlich für den Entwickler, weil sich damit
dokumentieren lässt, was ein Programm tatsächlich bewirkt.
Console.ReadLine();
//Warten, bis der Benutzer Eingabe-Taste drückt
Der Compiler überspringt den gesamten Text beginnend bei den beiden Schrägstrichen bis zum Ende
der Zeile. Einen mehrzeiligen Kommentar leiten Sie mit den Zeichen /* ein. Daraufhin überspringt der
Compiler alles, bis er die abschliessende Sequenz */ findet, die auch erst viele Zeilen weiter unten
erscheinen kann.
Tipp
Wenn das Ausgabefenster nicht erscheint, wählen Sie im Menü Ansicht den Befehl Ausgabe, um das
Fenster einzublenden.
Namespaces und Assemblys
Eine using-Anweisung bringt einfach die Elemente in einem Namespace in den Gültigkeitsbereich und
befreit Sie davon, die Namen von Klassen in Ihrem Code vollständig qualifizieren zu müssen. Klassen
werden zu Assemblys kompiliert. Eine Assembly ist eine Datei, die normalerweise die Erweiterung .dll
besitzt. Streng genommen sind aber ausführbare Programme mit der Dateierweiterung .exe ebenfalls
Assemblys.
Mirco De Roni
-5-
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
Eine Assembly kann viele Klassen enthalten. Die Klassen der .NET Framework-Klassenbibliothek wie
zum Beispiel System.Console werden in Assemblys bereitgestellt, die auf dem Computer zusammen
mit Visual Studio installiert werden. Die .NET Framework-Klassenbibliothek enthält mehrere Tausend
Klassen.
Die .NET-Klassenbibliothek ist in mehrere Assemblys aufgeteilt und zwar nach funktionellen Bereichen,
zu denen die enthaltenen Klassen in Beziehung stehen. Zum Beispiel gibt es eine Kernassembly, die
sämtliche allgemeinen Klassen wie zum Beispiel System.Console enthält und es gibt weitere
Assemblys mit Klassen für die Manipulation von Datenbanken, den Zugriff auf Webdienste, das erstellen
grafischer Benutzeroberflächen usw. Möchten Sie eine Klasse in einer Assembly verwenden, müssen Sie
Ihrem Projekt einen Verweis auf diese Assembly hinzufügen. Dann können Sie using-Anweisungen in
Ihrem Code einfügen, die die Elemente in den Namespaces in dieser Assembly in den Gültigkeitsbereich
bringen.
Zwischen einer Assembly und einem Namespace besteht nicht unbedingt eine 1:1-Verbindung. Eine
einzelne Assembly kann Klassen für mehrere Namespaces enthalten und ein und derselbe Namespace
kann sich über mehrere Assemblys erstrecken.
Im Projektmappen-Explorer klicken Sie mit der rechten Maustaste auf den Ordner Verweise und dann auf
Verweis hinzufügen.
Eine grafische Anwendung erstellen
Visual Studio 2008 bietet Ihnen zwei Ansichten einer grafischen Anwendung: die Entwurfsansicht und die
Codeansicht. Im Code- und Testeditorfenster modifizieren und verwalten Sie den Code und die Logik für
eine grafische Anwendung und im Fenster der Entwurfsansicht gestalten Sie das Layout der
Benutzeroberfläche.
Hinweis
Visual Studio 2008 bringt zwei Vorlagen für grafische Anwendungen mit: Windows-Forms-Anwendung
und WPF-Anwendung. Windows Forms ist eine Technologie, die mit .NET Framework 1.0 eingeführt
wurde. Die erweiterte Technologie WPF (Windows Presentation Foundation) ist seit .NET Framework 3.0
präsent. Gegenüber Windows Forms bietet sie viele zusätzliche Features und Fähigkeiten.
using
using
using
using
using
using
using
using
using
using
using
using
using
System;
System.Collections.Generic;
System.Linq;
System.Text;
System.Windows;
System.Windows.Controls;
System.Windows.Data;
System.Windows.Documents;
System.Windows.Input;
System.Windows.Media;
System.Windows.Media.Imaging;
System.Windows.Navigation;
System.Windows.Shapes;
namespace WpfApplication
{
/// <summary>
/// Interaktionslogik für Window1.xaml
/// </summary>
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
}
}
Mirco De Roni
-6-
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
2
Mit Variablen, Operatoren und Ausdrücke arbeiten
Anweisungen verstehen
Eine Anweisung ist ein Befehl, der eine bestimmte Aktion ausführt. In C# müssen Anweisungen ganz
bestimmten Regeln entsprechen, die das Format und die Konstruktion der Anweisungen beschreiben.
Die Gesamtheit dieser Regeln bezeichnet man als Syntax. Eine der einfachsten und gleichzeitig auch
wichtigsten Syntaxregeln von C# besagt, dass alle Anweisungen immer mit einem Semikolon
abzuschliessen sind.
Bezeichner verwenden
Bezeichner sind die Namen, mit denen Sie die Elemente – wie zum Beispiel Namespaces, Klassen,
Methoden und Variablen – im Programm ansprechen. In C# müssen Sie sich an die folgenden
Syntaxregeln halten, wenn Sie Bezeichner wählen:


Es sind nur Buchstaben (Gross- und Kleinbuchstaben), Ziffer und Unterstriche zulässig.
Ein Bezeichner muss mit einem Buchstaben beginnen, wobei ein Unterstrich als Buchstabe gilt.
Wichtig
C# ist eine Sprache, bei der unbedingt auf die Gross-/ Kleinschreibung zu achten ist.
Schlüsselwörter identifizieren
Die Programmiersprache C# reserviert 77 Bezeichner für den Eigenbedarf, die Sie nicht als Bezeichner
für Ihre Zwecke verwenden dürfen. Jedes dieser so genannten Schlüsselwörter hat eine spezielle
Bedeutung. Beispiele für Schlüsselwörter sind class, namespace und using.
Die folgende Tabelle zeigt alle Schlüsselwörter im Überblick:
abstract
as
base
bool
break
byte
case
catch
char
checked
class
const
continue
decimal
default
delegate
do
double
else
enum
event
explicit
extern
false
finally
fixed
float
for
foreach
goto
if
implicit
in
int
interface
internal
is
lock
long
namespace
new
null
object
operator
out
override
params
private
protected
public
readonly
ref
return
sbyte
sealed
short
sizeof
stackalloc
static
string
struct
switch
this
throw
true
try
typeof
uint
ulong
unchecked
unsafe
ushort
using
virtual
void
volatile
while
Tipp
Im Code- und Texteditorfenster von Visual Studio 2008 erscheinen die Schlüsselwörter nach der Eingabe
in blauer Schrift.
C# verwendet zudem die folgenden Bezeichner. Diese sind nicht für C# reserviert und Sie können
prinzipiell diese Namen als Bezeichner für Ihre eigenen Methoden, Variablen und Klassen verwenden.
Allerdings sollten Sie dies nach Möglichkeit vermeiden.
from
get
group
into
Mirco De Roni
join
let
orderby
partial
select
set
value
where
-7-
yield
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
Variablen verwenden
Eine Variable ist eine Speicherstelle, die einen Wert enthält. Jeder Variablen in einem Programm müssen
Sie einen eindeutigen Namen geben. Den Namen der Variablen verwenden Sie, um auf den Wert zu
verweisen, den die Variable speichert.
Variablen benennen
Für die Benennung von Variablen sollten Sie sich eine bestimmte Konvention aneignen, um Unklarheiten
hinsichtlich Ihrer selbst definierten Variablen von vornherein zu vermeiden. Die folgenden Liste gibt einige
Empfehlungen:




Verwenden Sie keine Unterstriche
Erstellen Sie keine Bezeichner, die sie lediglich durch die Gross-/ Kleinschreibung unterscheiden.
Verwenden Sie also im selben Programm keine Variable mit dem Namen vorname und eine
andere mit dem Namen Vorname, weil sich diese leicht verwechseln lassen.
Beginnen Sie den Namen mit einem Kleinbuchstaben
Besteht ein Bezeichner aus mehreren Wörtern, beginnen Sie das zweite und alle folgenden
Wörter mit einem Grossbuchstaben.
Hinweis
Bezeichner, die sich nur durch die Gross-/Kleinschreibung unterscheiden, können die Widerverwendung
von Klassen behindern, wenn Sie in Ihren Anwendungen auch andere Sprachen wie Visual Basic nutzen,
bei denen die Gross-/Kleinschreibung keine Rolle spielt.
Wichtig
Die beiden ersten Empfehlungen sollten Sie als obligatorisch behandeln, da sie sich auf die Kompatibilität
der Common Language Specification (CLS) beziehen. Möchten Sie Programme schreiben, die mit
anderen Programmiersprachen (beispielsweise Microsoft Visual Basic) zusammenarbeiten können,
müssen Sie diesen Empfehlungen folgen.
Variablen deklarieren
Variablen nehmen Werte auf. C# kann viele unterschiedliche Typen von Werten speichern und
verarbeiten – Ganzzahlen, Gleitkommazahlen und Zeichenfolgen. Wenn Sie eine Variable deklarieren,
müssen Sie angeben, welchen Typ von Daten sie speichern soll.
Den Typ und den Namen einer Variablen legen Sie in einer Deklarationsanweisung fest.
Hinweis
Microsoft Visual Basic-Programmierer sollten beachten, dass C# keine implizite Variablendeklaration
erlaubt. Alle Variablen müssen Sie vor ihrer Verwendung explizit deklarieren.
Nachdem die Variable deklariert wurde, kann ihr einen Wert zugewiesen werden. Die folgende
Anweisung weist der Variable vorname den Wert Mirco zu. Auch hier ist wieder das abschliessende
Semikolon erforderlich.
string vorname = "";
vorname = "Mirco";
Tipp
Wenn Sie im Code- und Texteditorfenster von Visual Studio 2008 den Mauszeiger auf eine Variable
setzen, erscheint nach kurzer Zeit ein Tooltipp, der den Wert der Variablen anzeigt.
Mit primitiven Datentypen arbeiten
C# verfügt über eine Reihe von vordefinierten Datentypen – die so genannten primitiven Typen. Die
folgende Tabelle zeigt die gebräuchlichsten primitiven Datentypen in C#.
Datentyp
int
long
float
Mirco De Roni
Beschreibung
Ganze Zahlen
Ganze Zahlen
Gleitkommazahlen einfacher
Genauigkeit
-8-
Grösse (Bits)
32
64
32
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
double
decimal
string
char
bool
Gleitkommazahlen doppelter
Genauigkeit
Währungswerte
Zeichenfolge
Einzelzeichen
Boolescher Wert
64
128
16 Bit je Zeichen
16
8
Arithmetische Operatoren verwenden
C# unterstützt die allgemein bekannten arithmetischen Operationen:
 Pluszeichen (+) für Addition
 Minuszeichen (-) für Subtraktion
 Sternchen (*) für Multiplikation
 Schrägstrich (/) für Division.
Diese Symbole bezeichnet man als Operatoren, da sie auf Werten operieren, um neue Werte zu
erzeugen.
Operatoren und Typen
Nicht alle Operatoren sind auf alle Datentypen anwendbar. Ob Sie einen Operator auf einen Wert
anwenden können, hängt vom Datentyp dieses Wertes ab. Beispielsweise lassen sich alle arithmetischen
Operatoren auf die Datentypen char, int, long, float, double und decimal anwenden. Jedoch
können Sie die arithmetischen Operatoren – mit Ausnahme des Plusoperators – nicht für Werte der
Datentypen string oder bool einsetzen.
Mit dem +-Operator können Sie zwei Zeichenfolgen miteinander verketten.
Tipp
Mit der Methode Int32.Parse des .NET Framework lässt sich ein Zeichenfolgenwert in eine Ganzzahl
umwandeln, wenn Sie arithmetische Berechnungen auf Werten, die in Zeichenfolgen enthalten sind,
ausführen müssen.
Numerische Typen und unendliche Werte
Zum Beispiel ist das Ergebnis der Division einer beliebigen Zahl durch null der Wert Infinity
(Unendlichkeit). Da er ausserhalb des Wertebereichs der Typen int, long und decimal liegt, führt die
Auswertung eines Ausdrucks wie zum Beispiel 2/0 zu einem Fehler. Die Typen double und float
besitzen jedoch einen speziellen Wert, der die Unendlichkeit darstellen kann. Der Ausdruck 2.0/0.0 liefert
damit den Wert Infinity.
C# unterstützt ausserdem einen nicht so bekannten Operator: den Restwert- oder Modulo-Operator, der
durch das Prozentsymbol (%) dargestellt wird. Das Ergebnis von x % y ist der Rest einer Division von x
durch y. So ist 5 % 2 gleich 1, da 5 dividiert durch 2 gleich 2 mit dem Rest 1 ergibt.
Die Operatorrangfolge steuern
Die Rangfolge der Operatoren regelt die Reihenfolge, in der die Operatoren eines Ausdrucks ausgewertet
werden.
2+3*4
Die Reihenfolge der Operationen ist wichtig, weil sie das Ergebnis verändert:


Wenn Sie zuerst die Addition und dann die Multiplikation ausführen, bildet das Ergebnis der
Addition (2 + 3) den linken Operanden des *-Operators und das Ergebnis des ganzen Ausdrucks
ist 5 * 4 oder 20.
Führen Sie zuerst die Multiplikation und dann die Addition aus, bildet das Ergebnis der
Multiplikation (3 * 4) den rechten Operanden des +-Operators und das Ergebnis des gesamten
Ausdrucks ist 2 + 12 oder 14.
In C# besitzen die multiplikativen Operatoren (*, /, %) einen höheren Vorrang als die additiven
Operatoren (+, -). Im oben angegebenen Ausdruck wird demnach zuerst die Multiplikation und dann die
Addition ausgeführt. Das Ergebnis lautet also 14.
Mirco De Roni
-9-
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
Mit Klammern können Sie die Operatorrangfolge ausser Kraft setzen und die Bindung von Operanden an
Operatoren gezielt ändern.
(2 + 3) * 4
Assoziativität und die Auswertung von Ausdrücken
Die Assoziativität (Orientierung) gibt an, in welcher Richtung (nach links oder rechts) die Operatoren
eines Operators ausgewertet werden.
4/2*6


Wenn Sie die Division zuerst ausführen, bildet das Ergebnis der Division (4 / 2) den linken
Operanden der Multiplikation und das Ergebnis des gesamten Ausdrucks ist (4 / 2) * 6 oder 12.
Führen Sie zuerst die Multiplikation aus, bildet das Ergebnis der Multiplikation (2 * 6) den rechten
Operanden des /-Operators und das Ergebnis des gesamten Ausdrucks ist 4 / (2 * 6) oder 4 / 12.
In diesem Fall bestimmt die Assoziativität der Operatoren, wie der Ausdruck ausgewertet wird. Die
Operatoren * und / sind linksassoziativ, d.h. die Operanden werden von links nach rechts ausgewertet.
Assoziativität und der Zuweisungsoperator
In C# ist das Gleichheitszeichen ein Operator. Alle Operatoren geben einen Wert zurück, der sich aus
den Operanden ergibt. Beim Zuweisungsoperator (=) ist das nicht anders. Er verknüpft zwei Operanden.
Der Operand auf seiner rechten Seite wird ausgewertet und dann im Operand auf seiner linken Seite
gespeichert. Der Wert des Zuweisungsoperators ist der Wert, der dem linken Operanden zugewiesen
wurde.
Variablen inkrementieren und dekrementieren
Mit dem Operator + können Sie zum Wert einer Variablen 1 addieren:
count = count + 1;
Da das Addieren von 1 in C# recht häufig vorkommt, gibt es für diesen Zweck einen eigenen Operator:
den Operator ++. Um die Variable count um 1 zu inkrementieren, schreibt man die folgende
Anweisung:
count ++;
Analog lässt sich in C# mit dem Operator -- von einer Variablen 1 subtrahieren, zum Beispiel:
count--;
Präfix und Postfix
Setzt man das Operatorsymbol vor die Variable, spricht man von der Präfixnotation des Operators, steht
das Operatorsymbol nach der Variablen, ist das die so genannte Postfixnotation.
count++;
++count;
count--;
--count;
//Postfix-Inkrement
//Präfix-Inkrement
//Postfix-Dekrement
//Präfx-Dekrement
Beispiel:
int zahl;
zahl = 10;
Console.WriteLine(zahl++);
zahl = 10;
Console.WriteLine(++zahl);
Mirco De Roni
//zahl ist 11, ausgegeben wird 10
//zahl ist 11, ausgegeben wird 11
- 10 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
Implizit typisierte lokale Variablen deklarieren
Der C#-Compiler kann den Typ eines Ausdrucks, mit dem Sie eine Variable initialisieren, schnell
herausfinden und Ihnen sagen, ob er dem Typ der Variablen entspricht. Ausserdem können Sie den C#Compiler anweisen, den Typ einer Variablen von einem Ausdruck herzuleiten und diesen Typ zu
verwenden. Dazu deklarieren Sie die Variable mit dem Schüsselwort var anstelle des Typs:
var zahl = 10;
var name = "Mirco De Roni";
Die Variablen zahl und name werden als implizit typisierte Variablen bezeichnet. Das Schlüsselwort var
veranlasst den Compiler, den Typ der Variablen aus den Typen der Ausdrücke, die zu ihrer Initialisierung
verwendet werden, herzuleiten.
Das Schlüsselwort var lässt sich nur verwenden, wenn Sie einen Ausdruck angeben, um eine Variable
zu initialisieren. Die folgende Deklaration ist nicht zulässig und verursacht einen Kompilierfehler:
var zahl;
Fehler Implizit typisierte lokale Variablen müssen initialisiert werden.
Mirco De Roni
- 11 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
3
Methoden schreiben und Gültigkeitsbereiche anwenden
Methoden deklarieren
Eine Methode ist eine benannte Sequenz von Anweisungen. Jede Methode besitzt einen Namen und ein
Körper. Der Name der Methode sollte ein aussagekräftiger Bezeichner sein, der auf den allgemeinen
Zweck der Methode hinweist. Der Methodenkörper enthält die eigentlichen Anweisungen, die beim
Aufrufen der Methode ausgeführt werden. Die meisten Methoden können Daten übernehmen, um sie zu
verarbeiten und Informationen zurückzugeben, die in der Regel das Ergebnis der Verarbeitung
repräsentieren. Methoden sind ein fundamentaler und leistungsfähiger Mechanismus.
Die Syntax zur Deklaration von Methoden
Die Syntax einer Microsoft Visual C#-Methode sieht folgendermassen aus:
rückgabeTyp methodenName (parameterListe)
{
//Anweisungen
}




Der rückgabeTyp ist der Name eines Typs und gibt an, welche Art von Informationen die
Methode zurückgibt. Wenn Sie eine Methode schreiben, die keinen Wert zurückgibt, müssen Sie
das Schlüsselwort void anstelle eines Rückgabetyps verwenden.
Der methodenName ist der Name, unter dem Sie die Methode aufrufen. Für Methodennamen
gelten die gleichen Regeln wie für Variablennamen.
Die optionale parameterListe beschreibt die Datentypen und Namen der Informationen, die Sie
an die Methode übergeben können.
Die Anweisungen im Körper der Methode sind die Codezeilen, die beim Aufruf der Methode
ausgeführt werden.
Wichtig
Programmierer, die bisher mit C, C++ oder Microsoft Visual Basic gearbeitet haben, sollten beachten,
dass C# keine globalen Methoden unterstützt. Alle Methoden müssen innerhalb einer Klasse erscheinen,
andernfalls lässt sich der Code nicht kompilieren.
Hinweis
Die Typen aller Parameter und den Rückgabetyp einer Methode müssen Sie explizit spezifizieren. Das
Schlüsselwort var dürfen Sie hierfür nicht verwenden.
Rückkehranweisungen schreiben
Wenn eine Methode Informationen zurückgeben soll, müssen Sie innerhalb der Methode eine
Rückkehranweisung schreiben. Dazu verwenden Sie das Schlüsselwort return mit einem
nachfolgenden Ausdruck, der den Rückgabewert berechnet und schliessen die Anweisung mit einem
Semikolon ab. Der Typ des Ausdrucks muss derselbe sein, den Sie für die Methode spezifiziert haben.
int calculate(int number1, int number2)
{
//...
return number1 + number2;
}
Die return-Anweisung sollte am Ende der Methode stehen, da sie die Ausführung der Methode
abschliesst. Alle nach der return-Anweisung stehenden Anweisungen werden nicht mehr ausgeführt.
Daher erhalten Sie auch eine Warnung vom Compiler, wenn sich hinter der return-Anweisung weitere
Anweisungen befinden.
Methoden aufrufen
Eine Methode rufen Sie nach ihrem Namen auf, um ihre programmierte Aufgabe durchführen zu lassen.
Wenn die Methode Informationen benötigt, müssen Sie die angeforderten Informationen bereitstellen.
Gibt die Methode Informationen zurück, sollten Sie diese Informationen in geeigneter Weise
weiterverarbeiten.
Mirco De Roni
- 12 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
Die Syntax zum Aufruf einer Methode spezifizieren
Die Syntax eines C#-Methodenaufrufs sieht folgendermassen aus:
ergebnis = methodenName (argumentListe);



Der methodenName muss exakt mit dem Namen der Methode übereinstimmen, die Sie aufrufen
wollen. Denken Sie daran, dass C# zwischen Gross- und Kleinschreibung unterscheidet.
Die Zuweisung ergebnis = ist optional. Wenn sie angegeben ist, nimmt die durch ergebnis
dargestellte Variable den Wert auf, den die Methode zurückgibt. Handelt es sich um eine voidMethode, müssen Sie die Zuweisung ergebnis = aus der Anweisung weglassen.
Mit der argumentListe geben Sie die optionalen Informationen an, die die Methode übernimmt.
Für jeden Parameter müssen Sie ein Argument bereitstellen und der Wert jedes Arguments muss
mit dem Typ des betreffenden Parameters übereinstimmen.
Wichtig
Die runden Klammern sind in jedem Methodenaufruf erforderlich, auch beim Aufruf von Methoden, die
keine Argumente übernehmen.
Beispiele von Aufrufvarianten, die nicht erfolgreich verlaufen:
calculate;
calculate();
calculate(10);
calculate("1", "Mirco De Roni");
//runde Klammern fehlen
//zu wenig Argumente
//zu wenig Argumente
//falsche Datentypen
Gültigkeitsbereiche anwenden
Wenn sich eine Variable an einer bestimmten Stelle in einem Programm verwenden lässt, sagt man, dass
die Variable in diesem Bereich gültig ist. Anders ausgedrückt ist der Gültigkeitsbereich einer Variablen
einfach der Bereich des Programms, in dem eine Variable verwendbar ist. Gültigkeitsbereiche sind
sowohl für Methoden als auch für Variablen definiert. Der Gültigkeitsbereich eines Bezeichners ist
verknüpft mit der Stelle der Deklaration, die den Bezeichner in das Programm einführt.
Lokale Gültigkeitsbereiche definieren
Die öffnende und die schliessende geschweifte Klammer, die den Körper einer Methode umfassen,
definieren einen Gültigkeitsbereich. Alle Variablen, die Sie innerhalb des Methodenkörpers definieren,
sind nur innerhalb der Methode gültig. Diese Variablen bezeichnet man als lokale Variablen.
class Person
{
void declaration()
{
string firstName = "";
string lastName = "";
int zipCode = 0;
string city = "";
}
void setValues()
{
firstName = "Mirco";
lastName = "De Roni";
zipCode = 6014;
city = "Luzern";
}
}
Dieser Code lässt sich nicht kompilieren, weil setValues() versucht die Variablen zu verwenden, die
aber nicht im Gültigkeitsbereich von setValues() liegen.
Mirco De Roni
- 13 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
Gültigkeitsbereiche auf Klassenebene definieren
Die durch die Klasse definierten Variablen bezeichnet man in C# als Felder. Im Unterschied zu lokalen
Variablen ist es mit Feldern möglich, Informationen zwischen Methoden gemeinsam zu nutzen bzw.
auszutauschen, wie es folgendes Beispiel zeigt:
class Person
{
string firstName = "";
string lastName = "";
int zipCode = 0;
string city = "";
void setValues()
{
firstName = "Mirco";
lastName = "De Roni";
zipCode = 6014;
city = "Luzern";
}
}
Die Variablen sind innerhalb der Klasse, aber ausserhalb der Methode setValues() definiert. Folglich
besitzen die Variablen den Gültigkeitsbereich auf Klassenebene und sind für alle Methoden in der Klasse
zugänglich.
Methoden überladen
Wenn sich zwei Bezeichner mit dem gleichen Namen im selben Gültigkeitsbereich befinden, sagt man,
dass sie überladen sind.
Wenn Sie beispielsweise zwei lokale Variablen mit dem gleichen Namen in derselben Methode
deklarieren, erhalten Sie einen Kompilierfehler angezeigt. Auch wenn Sie zwei Felder mit dem gleichen
Namen in derselben Klasse deklarieren oder zwei identische Methoden in derselben Klasse erstellen,
erhalten Sie Fehlermeldungen des Compilers.
static void Main(string[] args)
{
Console.WriteLine("Das Ergebnis lautet: ");
Console.WriteLine(10);
}
Überladen ist vor allem nützlich, wenn man die gleiche Operation auf unterschiedlichen Datentypen
ausführen muss. Eine Methode können Sie überladen, wenn die einzelnen Implementierungen
unterschiedliche Parametersätze haben, d.h. wenn zwar die Namen gleich sind, die Anzahl der
Parameter aber unterschiedlich ist oder wenn sich die Typen der Parameter unterscheiden.
Mirco De Roni
- 14 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
4
Entscheidungsanweisungen verwenden
Boolesche Variablen deklarieren
Das Ergebnis eines booleschen Ausdrucks ist immer entweder wahr oder falsch.
Microsoft Visual C# definiert den Datentyp bool. Eine Variable dieses Typs kann einen von zwei Werten
aufnehmen: true (wahr) oder false (falsch).
bool areYouReady = true;
Console.WriteLine(areYouReady);
Boolesche Operatoren verwenden
Ein boolescher Operator ist ein Operator, dessen Ergebnis entweder true oder false ist. C# definiert
mehrere boolesche Operatoren. Der einfachste boolesche Operator ist der logische Negationsoperator,
der durch das Symbol ! (Ausrufezeichen) repräsentiert wird.
Gleichheit und relationale Operatoren verstehen
Zwei gebräuchliche boolesche Operatoren bezeichnen die Gleichheit (==) und Ungleichheit (!=).
Operator
Bedeutung
Beispiel
==
!=
<
<=
>
>=
gleich
ungleich
kleiner als
kleiner oder gleich
grösser als
grösser oder gleich
jahr == 2009
jahr!= 0
jahr < 2010
jahr <= 2009
jahr > 2009
jahr >= 2010
Ergebnis, wenn jahr
gleich 2010 ist
false
true
false
false
true
true
Hinweis
Verwechseln Sie den Gleichheitsoperator == nicht mit dem Zuweisungsoperator =.
Bedingte logische Operatoren verstehen
C# stellt zwei weitere boolesche Operatoren zur Verfügung: das logische AND mit dem Symbol && und
das logische OR mit dem Symbol ||. Diese logischen Operatoren kombinieren boolesche Ausdrücke zu
grösseren Ausdrücken. Es handelt sich um binäre Operatoren, die den relationalen Operatoren ähnlich
sind, da ihre Ergebnisse entweder true oder false sind.
Das Ergebnis des &&-Operators ist nur dann true, wenn beide boolesche Operanden true sind.
int year = 2010;
bool validYear = (year <= 2012) && (year >= 2000);
Das Ergebnis des ||-Operators ist true, wenn mindestens einer seiner booleschen Operanden true
ist. Mit dem ||-Operator lässt sich bestimmen, ob irgendein Ausdruck einer Kombination von booleschen
Ausdrücken true ist.
int year = 2010;
bool validYear = (year < 2010) || (year >= 2010);
Operatorvorrang und Assoziativität im Überblick
Operatoren in derselben Kategorie besitzen die gleiche Priorität. Operatoren in einer höheren Kategorie
haben Vorrang vor Operatoren in einer niedrigeren Kategorie.
Kategorie
primär
unär
Mirco De Roni
Operatoren
()
++
-!
Beschreibung
Überschreibt Vorrang
Post-Inkrement
Post-Dekrement
Logisches NOT
- 15 -
Assoziativität
links
links
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
multiplikativ
additiv
relational
Gleichheit
bedingtes AND
bedingtes OR
Zuweisung
+
++
-*
/
%
+
<
<=
>
>=
==
!=
&&
||
=
Addition
Subtraktion
Prä-Inkrement
Prä-Dekrement
Multiplikation
Division
Modulo
Addition
Subtraktion
Kleiner als
Kleiner oder gleich
Grösser als
Grösser oder gleich
Gleich
Ungleich
Logisches AND
Logisches OR
links
links
links
links
links
links
rechts
Entscheidungen mit if-Anweisungen treffen
Mit einer if-Anweisung können Sie abhängig vom Ergebnis eines booleschen Ausdrucks entscheiden,
welcher von zwei unterschiedlichen Codeblöcken auszuführen ist.
Die Syntax der if-Anweisung verstehen
Die Syntax der if-Anweisung sieht wie folgt aus:
if (boolescherAusdruck)
{
//Anweisung1
}
else
{
//Anweisung2
}
Wenn boolescherAusdruck den Wert true ergibt, wird Anweisung1 ausgeführt; andernfalls hat
boolscherAusdruck den Wert false und das Programm führt Anweisung2 aus. Das Schlüsselwort else
und die nachfolgende Anweisung2 sind optional. Fehlt der else-Zweig, passiert nichts, wenn
boolscherAusdruck den Wert false ergibt.
Anweisungen in Blöcke gruppieren
Die oben angegebene Syntax der if-Anweisung spezifiziert eine einzelne Anweisung nach if
(boolscherAusdruck) und eine einzelne Anweisung nach dem Schlüsselwort else. Manchmal sind
mehrere Anweisungen auszuführen, wenn ein boolescher Ausdruck den Wert true ergibt. Man könnte
die Anweisungen in einer neuen Methode zusammenfassen und dann diese Methode aufrufen. Einfacher
ist aber, die Anweisungen in einem Block zu gruppieren. Ein Block ist einfach eine Folge von
Anweisungen, die in geschweifte Klammern eingeschlossen sind. Zudem beginnt ein Block einen neuen
Gültigkeitsbereich.
int seconds = 0;
int minutes = 0;
if (seconds == 59)
{
seconds = 0;
minutes++;
}
else
{
seconds++;
}
Mirco De Roni
- 16 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
if-Anweisungen verschachteln
Es ist möglich, if-Anweisungen innerhalb anderer if-Anweisungen zu verschachteln. Auf diese Art und
Weise können Sie eine Reihe von booleschen Ausdrücken verketten, die nacheinander getestet werden,
bis einer das Endergebnis true liefert.
int weekday = 6;
string dayName = "";
if(weekday == 1)
{
dayName = "Montag";
}
else if (weekday == 2)
{
dayName = "Dienstag";
}
else if (weekday == 3)
{
dayName = "Mittwoch";
}
else if (weekday == 4)
{
dayName = "Donnerstag";
}
else if (weekday == 5)
{
dayName = "Freitag";
}
else if (weekday == 6)
{
dayName = "Samstag";
}
else if (weekday == 7)
{
dayName = "Sonntag";
}
else
{
dayName = "Unbekannt";
}
switch-Anweisungen verwenden
Wenn Sie verschachtelte if-Anweisungen programmieren, sind manchmal die einzelnen ifAnweisungen einander recht ähnlich, weil sie alle einen identischen Ausdruck auswerten. Der einzige
Unterschied zwischen den if-Anweisungen besteht darin, dass sie das Ergebnis des Ausdrucks mit
einem anderen Wert vergleichen.
Im oberen Beispiel können Sie die verschachtelte if-Anweisung oftmals als switch-Anweisung
formulieren, um das Programm effizienter und verständlicher zu machen.
Die Syntax der switch-Anweisung verstehen
Die Syntax einer switch-Anweisung hat folgendes Aussehen:
switch (kontrollAusdruck)
{
case Ausdruck:
//Anweisungen
break;
...
default:
//Anweisungen
break;
}
Mirco De Roni
- 17 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
Der kontrollAusdruck wird einmal ausgewertet und die Anweisungen im case-Zweig, dessen Ausdruck
mit dem kontrollAusdruck identisch ist, werden bis zur break-Anweisung ausgeführt. Damit ist die
Abarbeitung der switch-Anweisung beendet und die Programmausführung setzt mit der ersten
Anweisung hinter der schliessenden geschweiften Klammer der switch-Anweisung fort.
Wenn kein Wert mit dem Wert von kontrollAusdruck übereinstimmt, werden die Anweisungen nach der
optionalen Marke default ausgeführt.
Die im letzten Beispiel gezeigte verschachtelte if-Anweisung können Sie mit einer switch-Anweisung
wie folgt formulieren:
switch (day)
{
case 1:
dayName
break;
case 2:
dayName
break;
case 3:
dayName
break;
case 4:
dayName
break;
case 5:
dayName
break;
case 6:
dayName
break;
case 7:
dayName
break;
default:
dayName
break;
}
= "Montag";
= "Dienstag";
= "Mittwoch";
= "Donnerstag";
= "Freitag";
= "Samstag";
= "Sonntag";
= "Unbekannt";
Regeln für die switch-Anweisung befolgen
Auch wenn die switch-Anweisung recht nützlich ist, kann man sie nicht uneingeschränkt verwenden.
Bei jeder switch-Anweisung müssen Sie sich an die folgenden Regeln halten:




Die switch-Anweisung lässt sich nur mit primitiven Datentypen wie int oder string
verwenden.
Die case-Marken müssen konstante Ausdrücke wie 10 oder "10" sein. Ist es erforderlich, die
Werte der case-Marken zur Laufzeit zu berechnen, müssen Sie mit einer if-Konstruktion
arbeiten.
Die case-Marken müsssen eindeutige Ausdrücke sein.
Es ist möglich, dieselben Anweisungen für mehr als einen Wert auszuführen.
Mirco De Roni
- 18 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
5
Verbundzuweisungen und Schleifen verwenden
Verbundzuweisungsoperatoren verwenden
Die folgende Tabelle gibt diese so genannten Verbundzuweisungsoperatoren im Überblick an.
Schreiben Sie nicht...
variable = variable
variable = variable
variable = variable
variable = variable
variable = variable
*
/
%
+
-
zahl;
zahl;
zahl;
zahl;
zahl;
sondern...
variable
variable
variable
variable
variable
*=
/=
%=
+=
-=
zahl;
zahl;
zahl;
zahl;
zahl;
Tipp
Die Verbundzuweisungsoperatoren besitzen den gleichen Vorrang und die gleiche Orientierung (nach
rechts verbunden) wie der einfache Zuweisungsoperator.
Schleifen mit while-Anweisungen schreiben
Mit einer while-Anweisung kann man eine Anweisung wiederholt ausführen, solange ein boolescher
Ausdruck true ist. Die Syntax der while-Anweisung lautet:
while (boolescherAusdruck)
{
//Anweisungen
}
Die while-Anweisung wertet boolescherAusdruck aus. Ist das Ergebnis true, führt sie die Anweisungen
aus und wertet dann erneut boolescherAusdruck aus. Ist der Ausdruck immer noch true, wird die
Anweisung wiedertholt ausgeführt und der Ausdruck wieder getestet. Dieser Vorrang setzt sich solange
fort, bis der boolesche Ausdruck den Wert false ergibt und damit die while-Schleife beendet ist.




Der zu testende Ausdruck muss ein boolescher Ausdruck sein.
Der boolesche Ausdruck muss in Klammern eingeschlossen sein.
Liefert der boolesche Ausdruck bereits bei der ersten Auswertung false, wird die Anweisung
überhaupt nicht ausgeführt.
Wenn zwei oder mehr Anweisungen unter der Steuerung einer while-Anweisung laufen sollen,
sind diese mit geschweiften Klammern als Block zu gruppieren.
Der Code im folgenden Beispiel gibt in einer while-Schleife die Zahlen von 1 bis 10 auf der Konsole aus:
int i = 1;
while (i <= 10)
{
Console.WriteLine(i);
i++;
}
Hinweis
Die Variable i in der while-Schleife steuert die Anzahl der ausgeführten Iterationen
(Schleifendurchläufe). Diese Konstruktion ist häufig anzutreffen und die Variable, die diese Rolle
übernimmt, bezeichnet man auch als Sentinel.
Schleifen mit for-Anweisungen schreiben
Mit der for-Schleife können Sie eine while-Schleife knapper formulieren, indem Sie die Initialisierung,
den booleschen Ausdruck und die Aktualisierung der Kontrollvariablen zusammenfassen. Die Syntax der
for-Anweisung lautet:
for (Initialisierung; boolescherAusdruck; Aktualisierung)
{
//Anweisungen
Mirco De Roni
- 19 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
}
Die bereits vorgestellte while-Schleife, die die Ganzzahlen von 1 bis 10 anzeigt, lässt sich mit der forSchleife wie folgt formulieren:
for (int i = 1; i <= 10; i++)
{
Console.WriteLine(i);
}
Die Initialisierung findet nur einmal am Anfang der Schleife statt. Wenn der boolesche Ausdruck den Wert
true ergibt, wird die Anweisung ausgeführt. Danach wird die Variable aktualisiert und der boolesche
Ausdruck erneut ausgewertet. Ist die Bedingung immer noch true, wird wieder die Anweisung
ausgeführt, die Variable aktualisiert, der boolesche Ausdruck ausgewertet usw.
Hinweis
Die Initialisierung, der boolesche Ausdruck und die Anweisung zur Aktualisierung der Steuervariablen in
einer for-Anweisung müssen immer durch Semikolons voneinander getrennt werden, selbst wenn Sie
diese Teile weglassen.
Den Gültigkeitsbereich von for-Anweisungen verstehen
Die Variable, die Sie im Körper der for-Anweisung deklariert haben, ist nur innerhalb der forAnweisung gültig und verschwindet, sobald die for-Schleife beendet ist.
Das folgende Beispiel erzeugt einen Kompilierfehler:
for (int i = 1; i <= 10; i++)
{
...
}
Console.WriteLine(i);
Schleifen mit do-Anweisungen schreiben
Die while- und for-Anweisungen testen den booleschen Ausdruck am Beginn der Schleife. Wenn also
der Ausdruck bereits beim allerersten Test false liefert, wird der Schleifenkörper überhaupt nicht
ausgeführt. Die do-Anweisung verhält sich anders. Sie testet ihren booleschen Ausdruck nach jeder
Iteration und führt somit den Schleifenkörper mindestens einmal aus.
Die Syntax der do-Anweisung sieht wie folgt aus:
do
{
//Anweisungen
} while (boolescher Ausdruck);
Der folgende Code stellt eine do-Version des Beispiels dar, Zahlen von 1 bis 10 auf der Konsole
auszugeben:
int i = 1;
do
{
Console.WriteLine(i);
i++;
} while (i <= 10);
Mirco De Roni
- 20 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
6
Fehler und Ausnahmen behandeln
Code probieren und Ausnahmen abfangen
In C# ist es relativ einfach, den Code, der den Hauptablauf des Programms implementiert, vom
Fehlerbehandlungscode zu trennen. Dies geschieht mit Ausnahmen und Ausnahme-Handlern.
try
{
//Anweisungen, die eine Exception auslösen könnten.
} catch (Exception ex)
{
//Wird eine Exception ausgelöst, enthält ex Informationen dazu.
}
Eine Ausnahme behandeln
Der catch-Handler verwendet eine Syntax ähnlich der eines Methodenparameters, um die
abzufangende Ausnahme zu spezifizieren. Wenn der Code eine Exception auslöst, wird die Variable ex
mit einem Objekt gefüllt, das die Einzelheiten der Ausnahme enthält. Die Message-Eigenschaft enthält
eine Textbeschreibung des Fehlers. Auf diese Informationen können Sie zurückgreifen, wenn Sie die
Ausnahme behandeln, die Details in einer Protokolldatei aufzeichnen oder dem Benutzer eine
aussagekräftige Fehlermeldung liefern.
Unbehandelte Ausnahmen
Wichtig
Nach dem Abfangen einer Ausnahme setzt die Programmausführung in der Methode fort, die den catchBlock enthält, der die Ausnahme abgefangen hat. Ist die Ausnahme in einer anderen Methode als der mit
dem catch-Handler aufgetreten, kehrt die Steuerung nicht zu der Methode zurück, die die Ausnahme
verursacht hat.
Mehrere catch-Handler verwenden
Unterschiedliche Fehler erzeugen unterschiedliche Arten von Ausnahmen, um unterschiedliche Arten von
Fehlern darzustellen. Um diese Situation zu entsprechen, können Sie mehrere catch-Handler
bereitstellen und nacheinander anordnen, wie es das folgende Beispiel zeigt:
try
{
//...
}
catch (NullReferenceException nEx)
{
//...
}
catch (OverflowException oEx)
{
//...
}
Mehrere Ausnahmen abfangen
Der von C# und Microsoft .NET Framework bereitgestellte Mechanismus zum Abfangen von Ausnahmen
ist recht umfassend. Im .NET Framework sind viele unterschiedliche Ausnahmen definiert und alle
Programme, die Sie schreiben, können die meisten davon auslösen!
Ausnahmen sind in Familien – so genannten Vererbungshierarchien – organisiert. Wenn Sie einen
catch-Handler für Exception vorsehen, fängt er jede mögliche Ausnahme ab, die auftreten kann.
Hinweis
Die Exception-Familie umfasst eine breite Palette von Ausnahmen, von denen viele für die
verschiedenen Teile des .NET Framework vorgesehen sind. Auch wenn einige davon recht ausgefallen
sind, ist es immerhin nützlich zu wissen, wie man sie abfängt.
Das nächste Beispiel zeigt, wie Sie alle möglichen Ausnahmen abfangen:
Mirco De Roni
- 21 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
try
{
//...
} catch (Exception ex) //Dies ist ein allgemeiner catch-Handler
{
//...
}
Ganzzahlarithmetik mit checked und unchecked
Tipp
Wenn Sie in einem Programm den kleinsten oder grössten Wert von int bestimmen möchten, können
Sie die Eigenschaften int.MinValue und int.MaxValue verwenden.
Unabhängig davon, wie Sie eine Anwendung kompilieren, können Sie mit den Schlüsselwörtern
checked und unchecked die Überlaufprüfungen in Teilen einer Anwendung selektiv ein- bzw.
ausschalten.
Geprüfte Anweisungen schreiben
Eine geprüfte Anweisung ist ein Anweisungsblock, der mit dem Schlüsselwort checked eingeleitet wird.
Alle Ganzzahlberechnungen in einer geprüften Anweisung lösen eine OverflowException–Ausnahme
aus, wenn eine Ganzzahlberechnung im Block einen Überlauf erzeugt.
int maxNumber = int.MaxValue;
checked
{
int willThrow = maxNumber++;
Console.WriteLine("Diese Zeile wird nie erreicht.");
}
Wichtig
Geprüft werden nur die Ganzzahlberechnungen, die sich direkt innerhalb des checked-Blocks befinden.
Handelt es sich beispielsweise bei einer der geprüften Anweisungen um einen Methodenaufruf, schliesst
die Überprüfung die Anweisungen in dieser Methode nicht mit ein.
Mit dem Schlüsselwort unchecked können Sie einen ungeprüften Anweisungsblock erzeugen. Alle
Ganzzahlberechnungen innerhalb eines ungeprüften Blocks werden dann nicht auf einen Überlauf hin
geprüft und lösen auch keine OverflowException aus.
int maxNumber = int.MaxValue;
unchecked
{
int wontThrow = maxNumber++;
Console.WriteLine("Diese Zeile wird erreicht.");
}
Geprüfte Ausdrücke schreiben
Mit den Schlüsselwörtern checked und unchecked können Sie auch die Überlaufprüfung in
Ganzzahlausdrücken steuern.
int willThrow = checked(int.MaxValue + 1);
int wontThrow = unchecked(int.MaxValue + 1);
Wichtig
Mit den Schlüsselwörtern checked und unchecked können Sie die Überlaufprüfung von
Gleitkommaberechnungen nicht steuern. Die Schlüsselwörter checked und unchecked funktionieren
nur bei arithmetischen Operationen mit ganzzahligen Werten.
Mirco De Roni
- 22 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
Ausnahmen auslösen
Die Klassenbibliotheken vom .NET Framework enthalten jede Menge Ausnahmeklassen, die für
bestimmte Situationen konzipiert sind. Meistens finden Sie eine Klasse, die Ihre Ausnahmebehandlung
sinnvoll beschreibt. Für unsere Zwecke ist die .NET Framework-Klasse
ArgumentOutOfRangeException passend. Eine Ausnahme lösen Sie mit der throw-Anweisung aus,
wie es in folgendem Beispiel zu sehen ist:
public static string getMonthName(int month)
{
switch (month)
{
case 1:
return "Januar";
case 2:
return "Februar";
case 3:
return "März";
...
default:
throw new ArgumentOutOfRangeException("Ungültiger Monat");
}
}
Die throw-Anweisung benötigt ein Ausnahmeobjekt, das auszulösen ist. Dieses Beispiel erzeugt mit
einem Ausdruck ein neues ArgumentOutOfRangeException-Objekt. Das Objekt wird über seinen
Konstruktor mit einer Zeichenfolge initialisiert, die seine Message-Eigenschaft füllt.
Einen finally-Block verwenden
Wenn eine Ausnahme ausgelöst wird, darf man nicht vergessen, dass die Ausnahme den Ablauf durch
das Programm verändert. Es ist also nicht garantiert, dass eine Anweisung immer ausgeführt wird, wenn
die vorherige Anweisung abgeschlossen ist – denn die vorherige Anweisung könnte eine Ausnahme
auslösen.
Um sicherzustellen, dass eine Anweisung immer – d.h. unabhängig davon, ob eine Ausnahme aufgerufen
ist oder nicht – ausgeführt wird, platziert man sie in einem finally-Block. Ein finally-Block steht
immer unmittelbar nach einem try-Block oder direkt im Anschluss an den letzten catch-Handler nach
einem try-Block. Der finally-Block wird in jedem Fall ausgeführt.
string path = openFileDialog.FileName;
FileInfo fileInfo = new FileInfo(path);
txtBoxFileName.Text = fileInfo.Name;
txtBoxSource.Text = "";
TextReader reader = null;
try
{
reader = fileInfo.OpenText();
string line = reader.ReadLine();
while (line != null)
{
txtBoxSource.Text += line + "\n";
line = reader.ReadLine();
}
}
finally
{
if (reader != null)
{
reader.Close();
}
}
Mirco De Roni
- 23 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
7
Klassen und Objekte erstellen und verwalten
Microsoft .NET Framework enthält sehr viele Klassen. Mit dem komfortablen Mechanismus von Klassen
modellieren Sie die Entitäten, die von Anwendungen manipuliert werden. Eine Entität kann ein
spezifisches Element (z.B. einen Kunden) oder etwas abstraktes (z.B. eine Transaktion) repräsentieren.
Ein grosser Teil im Entwurfsprozess jedes Systems beschäftigt sich damit, die wichtigen Entitäten
herauszuarbeiten und dann zu analysieren, welche Informationen sie benötigen und welche Funktionen
sie ausführen sollen. Felder speichern die Informationen, die eine Klasse aufnimmt und Methoden
implementieren die Operationen, die eine Klasse ausführen kann.
Was ist Klassifizierung?
Im Wort Klassifizierung steckt das Wort Klasse. Wenn Sie eine Klasse entwerfen, fassen Sie
Informationen systematisch in einer sinnvollen Entität zusammen. Es handelt sich dabei um eine
Klassifizierung, einen Vorgang, der jedem geläufig ist.
Zum Beispiel besitzen alle Autos gemeinsame Verhaltensweisen (lenken, bremsen, beschleunigen usw.)
und gemeinsame Attribute (ein Lenkrad, einen Motor usw.).
Was ist Kapselung?
Kapselung ist ein wichtiges Prinzip, wenn man Klassen definiert. Dahinter steckt die Idee, dass sich ein
Programm, das eine Klasse verwendet, nicht darum kümmern sollte, wie die Klasse eigentlich intern
arbeitet. Das Programm erzeugt einfach eine Instanz einer Klasse und ruft ihre Methoden auf. Eine
Klasse muss gegebenenfalls alle Arten von internen Zustandsinformationen verwalten, um ihre
verschiedene Methoden auszuführen. Diese zusätzlichen Zustandsinformationen und Aktivitäten werden
mithilfe der Klasse vor dem Programm verborgen. Demzufolge bezeichnet man Kapselung auch als das
Verbergen von Informationen.
Prinzipiell hat die Kapselung zwei Aufgaben:
 Methoden und Daten in einer Klasse zusammenfassen
 Die Zugänglichkeit der Methoden und Daten steuern
Eine Klasse definieren und verwenden
Wenn Sie eine neue Klasse erstellen wollen, dann machen Sie folgendes:
Im Projektmappen-Explorer klicken Sie mit der rechten Maustaste auf die Projektdatei und dann auf
Hinzufügen und anschliessend wählen Sie Klasse aus.
In C# wird die Klasse mit dem Schlüsselwort class definiert.
class Person
{
//Membervariablen
string m_FirstName = "";
string m_LastName = "";
int m_ZipCode = 0;
string m_City = "";
//Methoden
string getFirstName()
{
return m_FirstName;
}
void setFirstName(string firstName)
{
m_FirstName = firstName;
}
}
Sie erzeugen eine Variable, deren Typ Sie als Person spezifizieren und initialisieren dann die Variable
mit gültigen Daten, wie es folgendes Beispiel zeigt:
Person p = new Person();
Mirco De Roni
//Eine Klasse vom Typ Person instanziieren
- 24 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
Beachten Sie das Schlüsselwort new. Das Schlüsselwort new erzeugt eine neue Instanz einer Klasse.
Unter einem Objekt versteht man die Instanz einer Klasse.
Wichtig
Bringen Sie die Begriffe Klasse und Objekt nicht durcheinander. Eine Klasse ist die Definition eines Typs.
Ein Objekt ist eine Instanz dieses Typs und wird erzeugt, wenn das Programm läuft.
Den Zugriff kontrollieren
Wenn Sie Ihre Methoden und Daten in einer Klasse kapseln, bildet die Klasse eine Grenze zur äusseren
Welt. In der Klasse definierte Felder und Methoden sind anderen Methoden innerhalb der Klasse
zugänglich, aber nicht der Umgebung. Sie können die Definition eines Feldes oder einer Methode mit den
Schlüsselwörtern public und private modifizieren und damit steuern, ob das jeweilige Element von
aussen zugänglich ist.


Methoden oder Felder sind privat, wenn sie nur aus der Klasse selbst heraus zugänglich sind.
Um eine Methode oder ein Feld als privat zu deklarieren, schreiben Sie das Schlüsselwort
private vor die jeweilige Deklaration. Eigentlich ist das die Standardeinstellung, doch gehört es
zum Programmierstil, die privaten Methoden und Felder explizit zu kennzeichnen, um
Missverständnissen vorzubeugen.
Methoden oder Felder sind öffentlich, wenn sie sowohl aus der Klasse selbst heraus als auch von
ausserhalb der Klasse zugänglich sind. Um eine Methode oder ein Feld als öffentlich zu
deklarieren, schreiben Sie das Schlüsselwort public vor die jeweilige Deklaration.
class Person
{
//Membervariablen
private string m_FirstName = "";
private string m_LastName = "";
private int m_ZipCode = 0;
private string m_City = "";
//Methoden
public string getFirstName()
{
return m_FirstName;
}
public void setFirstName(string firstName)
{
m_FirstName = firstName;
}
}
Person p = new Person();
//Eine Klasse vom Typ Person instanziieren
p.setFirstName("Mirco");
string firstName = p.getFirstName();
Tipp
Die Felder in einer Klasse werden automatisch je nach ihrem Typ mit 0, false oder null initialisiert.
Allerdings empfiehlt es sich, die Initialisierung von Feldern explizit zu unterstützen.
Namenskonventionen und Zugänglichkeit
Klassennamen sollten mit einem Grossbuchstaben beginnen und die Namen der Konstruktoren müssen
exakt mit dem Namen der Klasse übereinstimmen.
Mit Konstruktoren arbeiten
Ein Konstruktor ist eine spezielle Methode mit dem gleichen Namen wie die Klasse. Der Konstruktor kann
Parameter übernehmen, aber keinen Wert zurückgeben. Wenn Sie selbst keinen Konstruktor schreiben,
generiert der Compiler automatisch einen Standardkonstruktor. Einen eigenen Standardkonstruktor
können Sie ganz leicht schreiben – fügen Sie einfach eine öffentliche Methode mit dem gleichen Namen
wie die Klasse hinzu und legen Sie keinen Rückgabewert fest.
Mirco De Roni
- 25 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
Das folgende Beispiel zeigt die Klasse Person mit einem Standardkonstruktor:
class Person
{
//Membervariablen
private string m_FirstName = "";
private string m_LastName = "";
private int m_ZipCode = 0;
private string m_City = "";
//Standardkonstruktor
public Person()
{
...
}
//Methoden
public string getFirstName()
{
return m_FirstName;
}
public void setFirstName(string firstName)
{
m_FirstName = firstName;
}
}
Hinweis
Im Sprachgebrauch von C# ist der Standardkonstruktor ein Konstruktor, der keine Parameter übernimmt.
Es spielt dabei keine Rolle, ob der Compiler ihn erzeugt oder Sie selbst ihn schreiben.
Beachten Sie, dass der Konstruktor als public markiert ist. Wenn dieses Schlüsselwort fehlt, ist der
Konstruktor privat. Ein privater Konstruktor lässt sich nicht von ausserhalb der Klasse aufrufen.
Konstruktoren überladen
Sie können unterschiedliche Versionen eines Konstruktors schreiben. Beispielsweise lässt sich die
Klasse Person mit einem Konstruktor ergänzen, der den Vorname als Parameter übernimmt:
class Person
{
//Membervariablen
private string m_FirstName = "";
private string m_LastName = "";
private int m_ZipCode = 0;
private string m_City = "";
//Standardkonstruktor
public Person()
{
...
}
//Überladener Konstruktor
public Person(string firstName)
{
setFirstName(firstName);
}
//Methoden
public string getFirstName()
{
return m_FirstName;
}
public void setFirstName(string firstName)
Mirco De Roni
- 26 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
{
m_FirstName = firstName;
}
}
Person p = new Person("Mirco");
string firstName = p.getFirstName();
Wenn Sie die Anwendung erstellen, ermittelt der Compiler anhand der Parameter, die Sie mit dem
Operator new spezifizieren, welcher Konstruktor aufgerufen werden soll.
Partielle Klassen
Eine Klasse versammelt eine Reihe von Methoden, Feldern und Konstruktoren sowie andere Elemente.
Eine funktionell umfangreiche Klasse kann ziemlich gross werden. Mit C# ist es möglich, den Quellcode
für eine Klasse in separate Dateien aufzuteilen. Dieses Feature nutzt Visual Studio 2008 für Windows
Presentation Foundation (WPF)-Anwendungen.
Wenn Sie eine Klasse auf mehrere Dateien aufteilen, definieren Sie die Teile der Klasse mit dem
Schlüsselwort partial in jeder Datei.
Person1.cs
partial class Person
{
//Standardkonstruktor
public Person()
{
...
}
//Überladener Konstruktor
public Person(string firstName)
{
setFirstName(firstName);
}
}
Person2.cs
partial class Person
{
//Membervariablen
private string m_FirstName = "";
private string m_LastName = "";
private int m_ZipCode = 0;
private string m_City = "";
//Methoden
public string getFirstName()
{
return m_FirstName;
}
public void setFirstName(string firstName)
{
m_FirstName = firstName;
}
}
Statische Methoden und Daten verstehen
In C# müssen alle Methoden innerhalb einer Klasse deklariert sein. Wenn Sie aber eine Methode oder
ein Feld als static deklarieren, können Sie die Methode aufrufen oder auf das Feld zugreifen, indem
Sie den Namen der Klasse verwenden. Es ist keine Instanz erforderlich.
Mirco De Roni
- 27 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
Beispiel:
class Circle
{
private double m_Diameter;
public static int m_NumCircles = 0;
private const double Pi = 3.1415;
//Standardkonstruktor
public Circle()
{
m_Diameter = 0;
m_NumCircles++;
}
//Überladener Konstruktor
public Circle(double d)
{
setDiameter(d);
m_NumCircles++;
}
//Methoden
public void setDiameter(double d)
{
m_Diameter = d;
}
public static double getArea(double d)
{
return Math.Pow(d, 2) * Pi / 4;
}
}
Console.WriteLine("Fläche: " + Circle.getArea(5.75));
Wenn Sie eine Methode als static definieren, hat sie keinen Zugriff auf irgendwelche Instanzfelder, die
für die Klasse definiert sind, sondern kann nur auf Felder zugreifen, die als static markiert sind.
Ein gemeinsam nutzbares Feld erstellen
Sie können mit dem Schlüsselwort static auch Felder definieren. Damit lässt sich ein einzelnes Feld
erzeugen und zwischen allen Objekten gemeinsam nutzen, die von derselben Klasse erstellt wurden.
Beispiel:
class Circle
{
...
public static int m_NumCircles = 0;
}
Console.WriteLine("Anzahl der Circle-Objekte: " + Circle.m_NumCircles);
Tipp
Statische Methoden bezeichnet man auch als Klassenmethoden. Dagegen spricht man nicht von
Klassenfeldern, sondern bleibt einfach bei der Bezeichnung statische Felder oder statische Variablen.
Ein statisches Feld mit dem Schlüsselwort const erstellen
Man kann auch ein statisches Feld deklarieren, dessen Wert sich nicht ändern lässt. Hierfür ist das
Schlüsselwort const (d.h. konstant) vorgesehen. Bei einem konstanten Feld erscheint zwar nicht das
static in der Deklaration, dennoch ist ein konstantes Feld auch statisch.
Mirco De Roni
- 28 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
Beispiel:
class Circle
{
...
private const double Pi = 3.1415;
}
Statische Klassen
Die Sprache C# erlaubt es zudem auch, eine Klasse als static zu deklarieren. Eine statische Klasse
kann nur statische Member enthalten. Eine statische Klasse hat einzig den Zweck, als Träger für
Hilfsmethoden und Felder zu fungieren und sie kann auch weder Instanzdaten noch Instanzmethoden
enthalten.
Wenn Sie zum Beispiel Ihre eigene Version der Klasse Math definieren, die nur statische Member
enthält, sieht die Klasse wie folgt aus:
public static class Math
{
public static double
{
...
return a;
}
public static double
{
...
return d;
}
public static double
{
...
return a;
}
public static double
{
...
return d;
}
...
}
Mirco De Roni
Sin(double a)
Cos(double d)
Tan(double a)
Sqrt(double d)
- 29 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
8
Werte und Verweise verstehen
Werttypvariablen und Klassen kopieren
Die Typen wie int, float, double und char werden zusammen als Werttypen bezeichnet. Für eine als
Werttyp deklarierte Variable generiert der Compiler Code, der einen ausreichend grossen Speicherblock
für die Aufnahme des entsprechenden Wertes zuordnet.
Bei Klassentypen liegen die Dinge anders. Wenn Sie eine Person-Variable deklarieren, generiert der
Compiler keinen Code, der einen ausreichend grossen Speicherblock für einen Person-Typ zuordnet. Er
reserviert lediglich einen kleinen Speicherbereich für den Verweis auf einen anderen Speicherblock (d.h.
dessen Adresse), der schliesslich ein Person-Objekt enthält. Die Adresse gibt die Position eines
Elements im Speicher an. Der Speicher für das Person-Objekt selbst wird nur zugeordnet, wenn ein
Objekt mit dem Schlüsselwort new erstellt wird. Eine Klasse ist ein Beispiel für einen Verweistyp.
Verweistypen speichern Verweise auf Speicherblöcke.
Hinweis
Die meisten primitiven Typen der Sprache C# sind Werttypen. Eine Ausnahme ist der Typ string, der
einen Verweistyp darstellt.
NULL-Werte und Typen, die NULL-Werte zulassen
Wenn Sie eine Variable deklarieren, sollten Sie sie immer auch initialisieren. Die Werttypen werden
häufig wie folgt deklariert:
int i = 0;
double d = 0.0;
Das folgende Codebeispiel initialisiert die Person-Variable p, weist sie später dann einer anderen
Instanz der Klasse Person zu:
Person p = new Person("Mirco");
Person copy = null;
if (copy == null)
{
copy = p;
}
Console.WriteLine("Vorname: " + p.getFirstName());
Console.WriteLine("Vorname: " + copy.getFirstName());
Die if-Anweisung stellt fest, ob die Variable initialisiert ist. In C# können Sie den Wert null jeder
Verweisvariablen zuweisen. Der Wert null bedeutet einfach, dass die Variable auf kein Objekt im
Speicher verweist.
Auf NULL festlegbare Typen verwenden
Der Wert null ist nützlich, um Verweistypen zu initialisieren. Allerdings ist null selbst ein Verweis und
kann keinem Werttyp zugewiesen werden. Deshalb ist die folgende Anweisung in C# nicht zulässig:
int i = null;
Allerdings definiert C# ein Modifizierer, mit dem Sie eine Variable als nullfähigen Werttyp deklarieren
können. Ein nullfähiger Werttyp verhält sich in ähnlicher Weise wie der ursprüngliche Wert, doch können
Sie ihm den Wert null zuweisen. Mit einem Fragezeichen (?) kennzeichnen Sie den Werttyp als
nullfähigen Typ:
int? i = null;
Einen nullfähigen Wert können Sie keiner Variablen eines normalen Werttyps zuweisen.
Mirco De Roni
- 30 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
Die Eigenschaften von auf NULL festlegbaren Typen verstehen
Die Eigenschaft HasValue zeigt an, ob ein auf NULL festlegbarer Typ einen Wert enthält oder null ist
und über die Eigenschaft Value können Sie den Wert eines auf NULL festlegbaren Typs, der nicht null
ist, abrufen:
int? i = null;
if (i.HasValue)
{
Console.WriteLine(i.Value);
}
else
{
i = 10;
}
Hinweis
Die Value-Eigenschaft eines auf NULL festlegbaren Typs ist schreibgeschützt. Mit dieser Eigenschaft
können Sie den Wert einer Variablen lesen, ihn aber nicht ändern. Eine auf NULL festlegbare Variable
aktualisieren Sie mit einer gewöhnlichen Zuweisungsanweisung.
Parameter mit ref und out übergeben
Parameter mit ref deklarieren
Wenn Sie einem Parameter das Schlüsselwort ref voranstellen, wird der Parameter ein Alias für das
eigentliche Argument und ist nicht mehr eine Kopie des Arguments. Bei einem ref-Parameter wirken
sich alle Änderungen, die Sie am Parameter vornehmen, automatisch auch auf das ursprüngliche
Argument aus, weil sowohl der Parameter als auch das Argument auf dasselbe Objekt verweisen.
static void Main(string[] args)
{
int arg = 25;
DoWork(ref arg);
Console.WriteLine(arg);
//gibt 26 aus
}
static void DoWork(ref int param)
{
param++;
}
Parameter mit out deklarieren
Der Compiler überprüft, ob der Code einem ref-Parameter einen Wert zugewiesen hat, bevor die
Methode aufgerufen wird. Allerdings gibt es auch Situationen, in denen man den Parameter in der
Methode selbst initialisieren und deshalb ein nicht initialisiertes Argument an die Methode übergeben
möchte. Für diesen Zweck ist das Schlüsselwort out vorgesehen.
Das Schlüsselwort out hat Ähnlichkeiten mit ref. Einem Parameter können Sie das Schlüsselwort out
voranstellen, sodass der Parameter zu einem Alias für das Argument wird.
Das Schlüsselwort out steht für output, also Ausgabe.
static void Main(string[] args)
{
int arg;
DoWork(out arg);
Console.WriteLine(arg); //gibt 25 aus
}
static void DoWork(out int param)
{
param = 25;
}
Mirco De Roni
- 31 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
Wie der Computerspeicher organisiert ist
Computer legen im Speicher die auszuführenden Programme und die von ihnen verwendeten Daten ab.
Betriebssysteme und Laufzeitumgebungen gliedern häufig den Speicher für die Aufnahme von Daten in
zwei getrennte Bereiche, die unterschiedlich verwaltet werden. Für diese beiden Speicherbereiche haben
sich die Bezeichnungen Stack und Heap eingebürgert. Stack und Heap haben zwei grundsätzlich
verschiedene Aufgaben:


Wenn Sie eine Methode aufrufen, wird der für ihre Parameter und lokalen Variablen benötigte
Speicher immer vom Stack angefordert. Endet die Methode, wird der für die Parameter und
lokalen Variablen angeforderte Speicher automatisch an den Stack zurückgegeben und ist
wieder verfügbar, wenn das Programm eine andere Methode aufruft.
Wenn Sie mit dem Schlüsselwort new und einem Konstruktoraufruf ein Objekt erstellen, wird der
für das Erstellen des Objekts erforderliche Speicher immer vom Heap angefordert.
Hinweis
Alle Werttypen werden auf dem Stack und alle Verweistypen (Objekte) auf dem Heap erstellt, obwohl der
Verweis selbst auf dem Stack untergebracht wird. Auf NULL festlegbare Typen sind Verweistypen und
werden somit auf dem Heap angelegt.
Die Klasse System.Object
Zu den wichtigsten Verweistypen in Microsoft .NET Framework gehört die Klasse object im Namespace
System.
Person p = new Person("Mirco");
object o = p;
Daten sicher konvertieren
Mit zwei recht nützlichen Operatoren hilft Ihnen C#, die Typumwandlung eleganter zu realisieren. Da sind
die Operatoren is und as.
Der Operator is
Mit dem Operator is können Sie überprüfen, ob der Typ eines Objekts dem erwarteten Typ entspricht:
Person p = new Person("Mirco");
object o = p;
if (o is Person)
{
Person temp = (Person)o;
}
Der Operator as
Der Operator as übernimmt eine ähnliche Rolle wie is, aber in einer etwas gekürzten Form. Den asOperator verwenden Sie wie folgt:
Person p = new Person("Mirco");
object o = p;
Person temp = o as Person;
if (temp != null)
{
...
//Typumwandlung war erfolgreich
}
Mirco De Roni
- 32 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
9
Werttypen mit Enumerationen und Strukturen erstellen
Mit Enumerationen arbeiten
Mit dem Schlüsselwort enum lässt sich ein Enumerationstyp (d.h. ein Aufzählungstyp) erstellen, dessen
Werte auf eine Menge symbolischer Namen beschränkt sind.
Einen Enumerationstyp deklarieren
Einen Enumerationstyp definieren Sie mit dem Schlüsselwort enum. Der folgende Beispielcode zeigt, wie
Sie einen Enumerationstyp für Jahreszeiten erstellen, dessen literale Werte auf die symbolischen Namen
Spring, Summer, Autumn und Winter beschränkt sind:
enum Season { Spring, Summer, Autumn, Winter }
Eine Enumeration verwenden
Nachdem Sie einen Enumerationstyp deklariert haben, können Sie ihn genau wie jeden anderen Typ
verwenden.
enum Season { Spring, Summer, Autumn, Winter }
Season colorful = Season.Autumn;
Console.WriteLine(colorful);
Literalwerte für eine Enumeration wählen
Jedem Element einer Enumeration ist ein bestimmet Zahlenwert zugeordnet. Standardmässig beginnt die
Nummerierung bei 0 für das erste Element und wird für das jeweils folgende um 1 erhöht. Es ist auch
möglich, den zugrunde liegenden Ganzzahlwert einer Enumerationsvariablen abzurufen. Dazu müssen
Sie ihren zugrunde liegenden Typ umwandeln.
enum Season { Spring, Summer, Autumn, Winter }
Season colorful = Season.Autumn;
Console.WriteLine((int)colorful);
//gibt '2' aus
Mit Strukturen arbeiten
Eine Struktur kann ihre eigenen Felder, Methoden und Konstruktoren genau wie eine Klasse besitzen.
Eine Struktur deklarieren
Einen eigenen Strukturtyp deklarieren Sie mit dem Schlüsselwort struct, an den sich der Name des
Typs und in einem Paar geschweifter Klammern der Körper der Struktur anschliessen. Das folgende
Beispiel zeigt eine Struktur Time mit drei öffentlichen Feldern:
struct Time
{
public int hours, minutes, seconds;
}
Wie bei Klassen ist es allerdings in den meisten Fällen nicht zu empfehlen, die Felder einer Struktur
öffentlich zu deklarieren. Es gibt keine Möglichkeit zu garantieren, dass die öffentlichen Felder gültige
Werte enthalten. Zum Beispiel könnte jedermann den Wert von minutes oder seconds auf einen Wert
grösser 60 setzen. Besser ist es also, die Felder als private zu deklarieren und die Struktur mit
Konstruktoren und Methoden zu versehen, um diese Felder zu initialisieren und zu ändern, wie es das
folgende Beispiel zeigt:
struct Time
{
private int hours, minutes, seconds;
public Time(int h, int m, int s)
{
hours = h % 24;
minutes = m % 60;
Mirco De Roni
- 33 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
seconds = s % 60;
}
public int
{
return
}
public int
{
return
}
public int
{
return
}
getHours()
hours;
getMinutes()
minutes;
getSeconds()
seconds;
}
Time t = new Time(2, 30, 15);
Console.WriteLine("Stunden: " + t.getHours());
Console.WriteLine("Minuten: " + t.getMinutes());
Console.WriteLine("Sekunden: " + t.getSeconds());
Mit Strukturen implementiert man vor allem einfache Konzepte, deren Hauptmerkmal ihr Wert ist.
Unterschiede zwischen Strukturen und Klassen
Auch wenn sich Strukturen und Klassen syntaktisch sehr ähnlich sind, gibt es einige wichtige
Unterschiede.


Für eine Struktur können Sie keinen Standardkonstruktor deklarieren.
In einer Klasse können Sie die Instanzfelder auch dort initialisieren, wo sie deklariert werden. Das
ist in einer Struktur nicht möglich.
Die folgende Tabelle fasst die Unterschiede zwischen Strukturen und Klassen noch einmal zusammen.
Frage
Handelt es sich um einen Werttyp
oder einen Verweistyp?
Werden Instanzen auf dem Stack
oder auf dem Heap angelegt?
Struktur
Eine Struktur ist ein Werttyp.
Klasse
Eine Klasse ist ein Verweistyp.
Strukturinstanzen heissen Werte
und existieren auf dem Stack.
Kann man einen
Standardkonstruktor deklarieren?
Generiert der Compiler einen
Standardkonstruktor, wenn man
einen eigenen Konstruktor
deklariert?
Initialisiert der Compiler
automatisch ein Feld, das man im
eigenen Konstruktor nicht
initialisiert hat?
Ist es erlaubt, Instanzfelder an der
Stelle ihrer Deklaration zu
initialisieren?
Nein
Klasseninstanzen heissen
Objekte und existieren auf dem
Heap.
Ja
Ja
Nein
Nein
Ja
Nein
Ja
Mirco De Roni
- 34 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
10 Arrays und Auflistungen verwenden
Was ist ein Array?
Ein Array (Datenfeld) ist eine ungeordnete Sequenz von Elementen. Alle Elemente eines Arrays besitzen
den gleichen Typ. Die Elemente eines Arrays sind in einem zusammenhängenden Speicherblock
abgelegt und man greift auf die Elemente über einen ganzzahligen Index zu.
Arrayvariablen deklarieren
Um eine Arrayvariable zu deklarieren, schreiben Sie den Namen des Elementtyps, ein Paar eckige
Klammern und den Variablennamen. Die eckigen Klammern signalisieren, dass die Variable ein Array ist.
int[] personalIDs;
//Persönliche Identifikationsnummern
Hinweis
Microsoft Visual Basic-Programmierer sollten darauf achten, hier eckige Klammern und keine runden
Klammern zu schreiben. Programmierer in C und C++ werden bemerken, dass die Grösse des Arrays
nicht nur Deklaration gehört.
Tipp
Es ist zweckmässig den Plural für Arraynamen zu verwenden.
Arrayinstanzen erzeugen
Arrays sind Verweistypen – unabhängig vom Typ ihrer Elemente. Eine Arrayvariable verweist also auf
eine Arrayinstanz auf dem Heap und speichert ihre Arrayelemente nicht direkt auf dem Stack. Wenn Sie
eine Klassenvariable deklarieren, wird für das Objekt erst dann Speicher zugewiesen, wenn Sie die
Instanz mit new erzeugen. Bei Arrays ist es genauso: Die Grösse eines Arrays geben Sie noch nicht an,
wenn Sie die Arrayvariable deklarieren, sondern erst, wenn Sie die Arrayinstanz tatsächlich erstellen.
Um eine Arrayinstanz zu erzeugen, schreiben Sie das Schlüsselwort new, den Namen des Elementtyps
und in eckigen Klammern die Grösse des zu erzeugenden Arrays.
personalIDs = new int[5];
Um beispielsweise ein zweidimensionales Array anzulegen, erstellen Sie ein Array, das zwei ganzzahlige
Indizes verlangt.
int[,] table = new int[2, 4];
Arrayvariablen initialisieren
int[] personalIDs = new int[5] { 2, 4, 6, 8, 10 };
Ein implizit typisiertes Array erstellen
var names = new[] { "Mirco", "Jessica", "Victoria", "Francesco" };
Auf einzelne Elemente des Arrays zugreifen
Um auf ein einzelnes Arrayelement zuzugreifen, geben Sie einen Index an, der das gewünschte Element
bezeichnet. Arrayindizes sind nullbasiert. Das erste Element eines Arrays befindet sich am Index 0.
Console.WriteLine("Name: " + names[0]);
Ein Array durchlaufen
Für Arrays sind mehrere nützliche Eigenschaften und Methoden vordefiniert. Die Eigenschaft Length
gibt darüber Auskunft, wie viele Elemente ein Array enthält. Die Eigenschaft Length können Sie auch
nutzen, um die Elemente eines Arrays in einer for-Anweisung zu durchlaufen. Der folgende
Beispielcode gibt alle Werte des Arrays names auf der Konsole aus:
var names = new[] { "Mirco", "Jessica", "Victoria", "Francesco" };
Mirco De Roni
- 35 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
for (int index = 0; index < names.Length; index++)
{
Console.WriteLine("Name: " + names[index]);
}
Das folgende Codefragment hat die gleiche Funktonalität wie das vorherige Beispiel, nur verwendet es
foreach statt for:
var names = new[] { "Mirco", "Jessica", "Victoria", "Francesco" };
foreach (string aName in names)
{
Console.WriteLine("Name: " + aName.ToString());
}




Die foreach-Anweisung durchläuft immer das gesamte Array. Mit einer for-Schleife ist es
dagegen problemlos möglich, nur einen bestimmten Teil des Arrays zu bearbeiten oder
bestimmte Elemente zu überspringen.
Die foreach-Anweisung durchläuft das Array immer vom Index 0 bis zum Index Length – 1. Mit
einer for-Schleife können Sie das Array auch von hinten nach vorn durchlaufen.
Wenn Sie innerhalb der Schleife den Index des Elements und nicht nur seinen Wert benötigen,
sind Sie auf eine for-Schleife angewiesen.
Eine for-Schleife ist auch erforderlich, wenn Sie die Elemente des Arrays modifizieren möchten,
da es sich bei der Iterationsvariablen der foreach-Anweisung um eine schreibgeschützte Kopie
der einzelnen Arrayelemente handelt.
Die Iterationsvariable können Sie als var deklarieren und es dem C#-Compiler überlassen, den Typ der
Variablen aus dem Typ der Elemente im Array herzuleiten. Dies ist vor allem nützlich, wenn Sie den Typ
der Elemente im Array nicht kennen.
Was sind Auflistungsklassen?
Arrays sind nützlich, haben aber auch ihre Grenzen. Allerdings stellen Arrays nur eine Möglichkeit dar,
Elemente des gleichen Typs zu gruppieren. Das Microsoft .NET Framework bietet mehrere Klassen, die
ebenfalls Elemente in andere spezialisierten Formen sammeln. Es handelt sich um Auflistungsklassen
(Collections), die im Namespace System.Collections existieren.
Die grundlegenden Auflistungsklassen übernehmen, speichern und liefern ihre Elemente als Objekte. Der
Elementtyp einer Auflistungsklasse ist also object.
Die Auflistungsklasse ArrayList
Die Klasse ArrayList ist nützlich, wenn Sie mit Arrayelementen hantieren müssen. In bestimmten
Situationen können normale Arrays zu restriktiv sein:



Wenn Sie die Grösse eines Arrays verändern wollen, müssen Sie ein neues Array erzeugen, die
Elemente kopieren und dann alle Arrayverweise auf das ursprüngliche Array aktualisieren, damit
diese auf das neue Array zeigen.
Wenn Sie ein Element aus dem Array entfernen wollen, müssen Sie alle nachfolgenden
Elemente um einen Platz nach vorn verschieben.
Wenn Sie in ein Array ein Element einfügen wollen, müssen Sie alle Elemente ab der
gewünschten Einfügeposition um eine Position nach hinten verschieben, um einen freien Platz zu
schaffen. Allerdings verlieren Sie dabei das letzte Element des Arrays!
Die Klasse ArrayList beseitigt diese Einschränkungen:



Mit der Methode Remove lässt sich ein Element aus einer ArrayList entfernen. Die
ArrayList ordnet ihre Elemente automatisch neu an.
Die Methode Add der ArrayList fügt ein Element am Ende der Auflistung an. Die ArrayList
passt ihre Grösse bei Bedarf automatisch an.
Mit der Methode Insert fügen Sie ein Element in der Mitte einer ArrayList ein. Auch in
diesem Fall passt die ArrayList bei Bedarf ihre Grösse automatisch an.
Mirco De Roni
- 36 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________

Auf ein vorhandenes Element in einem ArrayList-Objekt können Sie mit der normalen
Arraynotation verweisen, d.h. den Index des Elements in eckigen Klammern angeben.
Das folgende Beispiel zeigt, wie Sie eine ArrayList erstellen, manipulieren und den Inhalt durchlaufen:
using System;
using System.Collections;
ArrayList numbers = new ArrayList();
//Die ArrayList füllen
foreach (int nr in new int[10] { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20 })
{
numbers.Add(nr);
}
//Ein Element an die vorletzte Position einfügen
numbers.Insert(numbers.Count - 1, 40);
//Entferne das Element, dessen Wert 8 beträgt
numbers.Remove(8);
//Entferne das Element an der Position 4
numbers.RemoveAt(4);
//Durchlaufe die Elemente mit einer for-Schleife
for (int i = 0; i < numbers.Count; i++)
{
Console.WriteLine(numbers[i]);
}
//Durchlaufe die Elemente mit einer foreach-Anweisung
foreach (int aNr in numbers)
{
Console.WriteLine(aNr);
}
Der Code liefert folgende Ausgabe:
2
4
6
10
14
16
18
40
20
Die Auflistungsklasse Queue
Die Klasse Queue (Warteschlange) implementiert einen FIFO-Mechanismus (First In, First Out). Ein
Element wird von hinten in die Warteschlange eingefügt (Enqueue-Operation) und von vorn aus der
Warteschlange entnommen (Dequeue-Operation).
Der folgende Code realisiert eine Warteschlange und ihre Operationen:
using System;
using System.Collections;
Queue numbers = new Queue();
//Die Warteschlange füllen
foreach (int nr in new int[4] { 2, 4, 6, 8})
{
Mirco De Roni
- 37 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
numbers.Enqueue(nr);
Console.WriteLine(nr + " wurde in die Warteschlange aufgenommen");
}
//Die Warteschlange durchlaufen
foreach (int aNr in numbers)
{
Console.WriteLine(aNr);
}
//Die Warteschlange leeren
while (numbers.Count > 0)
{
Console.WriteLine(numbers.Dequeue() + " hat die Warteschlange verlassen");
}
Dieser Code liefert folgende Ausgabe:
2 wurde in die Warteschlange aufgenommen
4 wurde in die Warteschlange aufgenommen
6 wurde in die Warteschlange aufgenommen
8 wurde in die Warteschlange aufgenommen
2
4
6
8
2 hat die Warteschlange verlassen
4 hat die Warteschlange verlassen
6 hat die Warteschlange verlassen
8 hat die Warteschlange verlassen
Die Auflistungsklasse Stack
Die Klasse Stack (Stapel) implementiert einen LIFO-Mechanismus (Last In, First Out). Um ein Element
in den Stack einzufügen, wird es auf die Spitze des Stapels gelegt (Push-Operation) und um es aus dem
Stack zu entfernen, wird es von der Spitze des Stapels genommen (Pop-Operation).
using System;
using System.Collections;
Stack numbers = new Stack();
//Den Stack füllen
foreach (int nr in new int[4] { 2, 4, 6, 8 })
{
numbers.Push(nr);
Console.WriteLine(nr + " wurde auf den Stack gelegt");
}
//Den Stack durchlaufen
foreach (int aNr in numbers)
{
Console.WriteLine(aNr);
}
//Den Stack leeren
while (numbers.Count > 0)
{
Console.WriteLine(numbers.Pop() + " wurde vom Stack genommen");
}
Mirco De Roni
- 38 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
Dieses Programm erzeugt folgende Ausgabe:
2 wurde auf den Stack gelegt
4 wurde auf den Stack gelegt
6 wurde auf den Stack gelegt
8 wurde auf den Stack gelegt
8
6
4
2
8 wurde vom Stack genommen
6 wurde vom Stack genommen
4 wurde vom Stack genommen
2 wurde vom Stack genommen
Die Auflistungsklasse Hashtable
Die Hashtable verwaltet intern zwei object-Arrays – eines für die Schlüssel, von denen Sie die
Zuordnung herstellen und eines für die Werte, auf die Sie abbilden. Wenn Sie ein Schlüssel-Wert-Paar in
eine Hashtable einfügen, zeichnet sie automatisch auf, welcher Schlüssel zu welchem Wert gehört. Aus
dem Konzept der Hashtable-Klasse ergeben sich einige wichtige Konsequenzen:



Eine Hashtable kann keine doppelten Schlüssel enthalten. Wenn Sie mit der Methode Add
einen Schlüssel hinzufügen möchten, der bereits im Schlüsselarray vorhanden ist, wird eine
Ausnahme ausgelöst.
Intern ist eine Hashtable eine Datenstruktur mit geringer Datendichte, die am besten
funktioniert, wenn ihr genügend Speicher zur Verfügung steht. Die Grösse einer Hashtable im
Speicher kann schnell zunehmen, wenn Sie weitere Elemente einfügen.
Wenn Sie eine Hashtable mit einer foreach-Anweisung durchlaufen, erhalten Sie einen
DictionaryEntry zurück. Die Klasse DictionaryEntry bietet den Zugriff auf die
Schlüssel- und Wertelemente in beiden Arrays über die Key- und die Value-Eigenschaften.
using System;
using System.Collections;
Hashtable ages = new Hashtable();
//Die Hashtable füllen
ages.Add("Mirco", 18);
ages.Add("Jessica", 20);
ages.Add("Victoria", 26);
ages.Add("Francesco", 34);
//Die Hashtable durchlaufen
foreach (DictionaryEntry anElement in ages)
{
string name = (string)anElement.Key;
int age = (int)anElement.Value;
Console.WriteLine("Name: " + name + ", Alter: " + age);
}
Die Ausgabe dieses Programms lautet:
Name: Mirco, Alter: 18
Name: Jessica, Alter: 20
Name: Victoria, Alter: 26
Name: Francesco, Alter: 34
Mirco De Roni
- 39 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
Die Klasse SortedList
Die Klasse SortedList ist der Klasse Hashtable dahingehend ähnlich, dass sie die Zuordnung von
Schlüsseln zu Werten erlaubt. Der wesentliche Unterschied besteht darin, dass das Schlüsselarray
immer sortiert ist.
Wie die Klasse Hashtable kann eine SortedList keine doppelten Schlüssel enthalten. Wenn Sie eine
SortedList mit einer foreach-Anweisung durchlaufen, erhalten Sie einen DictionaryEntry
zurück. Allerdings werden die DictionaryEntry-Objekte sortiert nach der Key-Eigenschaft
zurückgegeben.
using System;
using System.Collections;
SortedList ages = new SortedList();
//Die SortedList füllen
ages.Add("Mirco", 18);
ages.Add("Jessica", 20);
ages.Add("Victoria", 26);
ages.Add("Francesco", 34);
//Die SortedList durchlaufen
foreach (DictionaryEntry anElement in ages)
{
string name = (string)anElement.Key;
int age = (int)anElement.Value;
Console.WriteLine("Name: " + name + ", Alter: " + age);
}
Die Ausgabe dieses Programms ist alphabetisch nach dem Namen sortiert:
Name: Francesco, Alter: 34
Name: Jessica, Alter: 20
Name: Mirco, Alter: 18
Name: Victoria, Alter: 26
Arrays und Auflistungen im Vergleich
Die folgende Übersicht fasst die wichtigsten Unterschiede zwischen Arrays und Auflistungen zusammen:



Bei einem Array deklarieren Sie den Typ der Elemente, die das Array speichert. Bei einer
Auflistung geben Sie keinen Typ an, weil sie ihre Elemente als Objekte speichert.
Eine Arrayinstanz besitzt eine feste Grösse und kann weder wachsen noch schrumpfen. Eine
Auflistung passt ihre Grösse bei Bedarf dynamisch an.
Ein Array kann mehrere Dimensionen umfassen. Eine Auflistung ist linear.
Mirco De Roni
- 40 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
11 Parameterarrays verstehen
Arrayargumente verwenden
Um beispielsweise die kleinste Zahl unter mehreren int-Werten zu ermitteln, können Sie eine statische
Methode Min schreiben, die als einzelnen Parameter ein Array von int-Werten übernimmt:
class Util
{
public static int Min(params int[] paramList)
{
if (paramList == null || paramList.Length == 0)
{
throw new ArgumentException("Util.Min: Nicht genügend Argumente");
}
int currentMin = paramList[0];
foreach (int i in paramList)
{
if (i < currentMin)
{
currentMin = i;
}
}
return currentMin;
}
}
Console.WriteLine(Util.Min(10, 9, 8, 7, 6, 5, 4, 3, 2, 1));
Das Schlüsselwort params dient als Modifizierer für Arrayparameter. Es bedeutet für die Methode Min,
dass man sie mit einer beliebigen Anzahl von Parametern aufrufen kann.
Mirco De Roni
- 41 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
12 Vererbung richtig einsetzen
Was ist Vererbung?
Vererbung im Bereich der Programmierung meint in erster Linie Klassifizierung – Beziehungen zwischen
Klassen.
Vererbung einsetzen
Basisklassen und abgeleitete Klassen
Eine Klasse, die von einer anderen Klasse erbt, wird mit folgender Syntax deklariert:
class AbgeleiteteKlasse : BasisKlasse
{
...
}
Die abgeleitete Klasse erbt von der Basisklasse und die Methoden der Basisklasse werden ebenfalls Teil
der abgeleiteten Klasse. In C# darf eine Klasse von höchstens einer anderen Klasse erben, d.h. eine
Klasse darf nicht von zwei oder mehreren anderen Klassen abgeleitet werden.
Wichtig
Vererbung lässt sich nicht mit Strukturen einsetzen. Eine Struktur kann weder von einer Klasse noch von
einer anderen Struktur erben.
class Vehicle
{
public void StartEngine(string noiseToMakeWhenStarting)
{
Console.WriteLine("Motor starten: {0}", noiseToMakeWhenStarting);
}
public void StopEngine(string noiseToMakeWhenStopping)
{
Console.WriteLine("Motor anhalten: {0}", noiseToMakeWhenStopping);
}
public virtual void Drive()
{
Console.WriteLine("Standardimplementierung der Methode Drive");
}
}
class Car : Vehicle
{
public void Accelerate()
{
Console.WriteLine("Beschleunigen");
}
public void Brake()
{
Console.WriteLine("Bremsen");
}
public override void Drive()
{
Console.WriteLine("Autofahren");
}
}
Mirco De Roni
- 42 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
Die Konstruktoren der Basisklasse aufrufen
Eine abgeleitete Klasse erhält automatisch alle Felder von der Basisklasse. Diese Felder sind
normalerweise zu initialisieren, wenn ein Objekt erstellt wird. In der Regel führt man eine derartige
Initialisierung in einem Konstruktor durch. Es gehört zum guten Programmierstil, in einem Konstruktor der
abgeleiteten Klasse als Teil der Initialisierung den Konstruktor für ihre Basisklasse aufzurufen. Mit dem
Schlüsselwort base rufen Sie einen Basisklassenkonstruktor auf, wenn Sie den Konstruktor für eine
erbende Klasse definieren.
class Vehicle
//Basisklasse
{
public Vehicle()
//Konstruktor für Basisklasse
{
...
}
}
...
class Car : Vehicle
{
public Car()
: base()
{
...
}
...
}
//abgeleitete Klasse
Klassen zuweisen
Console.WriteLine("\nAutofahrt");
Car car = new Car();
car.StartEngine("Brumm brumm");
car.Accelerate();
car.Drive();
car.Brake();
car.StopEngine("Puff puff");
Console.WriteLine("\nPolymorphie testen");
Vehicle v = car;
v.Drive();
Überschreibungsmethoden
Wenn in einer Basisklasse eine Methode als virtual deklariert ist, kann eine abgeleitete Klasse mit
dem Schlüsselwort override eine andere Implementierung dieser Methode deklarieren.
Wenn Sie mithilfe der Schlüsselwörter virtual und override polymorphe Methoden deklarieren,
müssen Sie ein paar Regeln beachten:






Eine private Methode dürfen Sie nicht mit den Schlüsselwörtern virtual oder override
deklarieren. Andernfalls erhalten Sie eine Fehlermeldung des Compilers.
Die beiden Methoden müssen identisch sein, d.h. sie müssen den gleichen Namen, die gleichen
Parametertypen und den gleichen Rückgabetyp besitzen.
Die beiden Methoden müssen den gleichen Zugriffsmodifizierer haben.
Es lassen sich nur virtuelle Methoden überschreiben.
Ist die Methode in der abgeleiteten Klasse nicht mit dem Schlüsselwort override deklariert,
überschreibt sie auch nicht die Methode.
Eine mit dem Schlüsselwort override deklarierte Methode ist implizit virtuell und kann selbst in
einer abgeleiteten Klasse überschrieben werden.
Geschützter Zugriff
Die Schlüsselwörter private und public sind die beiden Zugriffsmodifiziere: Auf öffentliche Felder und
Methoden einer Klasse kann jeder zugreifen, während private Felder und Methoden einer Klasse nur für
die Klasse selbst zugänglich sind.
Mirco De Roni
- 43 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
Vererbung ist ein leistungsfähiger Mechanismus, um Klassen zu verbinden und zwischen einer
abgeleiteten Klasse und ihrer Basisklasse besteht zweifellos eine sehr spezielle enge Beziehung. Häufig
ist es nützlich, wenn abgeleitete Klassen auf bestimmte Member der Basisklasse zugreifen dürfen,
während dieselben Member gegenüber Klassen, die nicht zur Hierarchie gehören, ausgeblendet werden.
In dieser Situation können Sie Member mit dem Schlüsselwort protected (geschützt) markieren.


Ist eine Klasse A von einer anderen Klasse B abgeleitet, kann sie auf die geschützten Member
der Klasse B zugreifen. Mit anderen Worten ist ein geschützter Member der Klasse B innerhalb
der abgeleiteten Klasse A praktisch öffentlich.
Ist eine Klasse A nicht von einer anderen Klasse B abgeleitet, kann sie auf einen geschützten
Member der Klasse B nicht zugreifen. Mit anderen Worten ist innerhalb der Klasse A ein
geschützter Member der Klasse B praktisch privat.
Öffentliche Felder verletzen das Prinzip der Kapselung, da alle Benutzer der Klasse direkten und
uneingeschränkten Zugriff auf die Felder haben.
Hinweis
Auf einen geschützten Member einer Basisklasse können Sie nicht nur in einer abgeleiteten Klasse
zugreifen, sondern auch in Klassen, die von der abgeleiteten Klasse abgeleitet sind. Ein geschützter
Member der Basisklasse bewahrt seine geschützte Zugriffseigenschaft in einer abgeleiteten Klasse und
ist auch in davon abgeleiteten Klassen zugänglich.
Mirco De Roni
- 44 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
13 Schnittstellen erstellen und abstrakte Klassen deklarieren
Schnittstellen verstehen
Wenn eine Klasse eine Schnittstelle implementiert, garantiert die Schnittstelle, dass die Klasse alle in der
Schnittstelle spezifizierten Methoden enthält. Dieser Mechanismus stellt sicher, dass man die Methode
auf allen Objekten in der Auflistung aufrufen und die Objekte sortieren kann.
Die Schnittstelle sagt Ihnen, was der Name, der Rückgabetyp und die Parameter der Methode sind.
Dagegen hat die Schnittstelle nichts damit zu tun, wie die Methode konkret implementiert ist. Die
Schnittstelle gibt darüber Auskunft, wie Sie ein Objekt verwenden möchten und nicht, wie die
Verwendung überhaupt implementiert ist.
Schnittstellensyntax
Eine Schnittstelle deklarieren Sie mit dem Schlüsselwort interface anstelle von class oder struct.
Innerhalb der Schnittstelle deklarieren Sie Methoden genauso wie in einer Klasse oder Struktur, ausser
dass Sie den Methodenkörper durch ein Semikolon ersetzen und niemals einen Zugriffsmodifizierer
(public, private oder protected) angeben.
Der folgende Beispielcode zeigt eine Schnittstellendeklaration:
interface IDescription
{
void setDescription(string s);
}
Tipp
Die Dokumentation zu Microsoft .NET Framework empfiehlt Schnittstellennamen den Grossbuchstaben I
als Präfix voranzustellen, um deutlich auf eine Schnittstelle (Interface) hinzuweisen.
Schnittstelleneinschränkungen
Als grundlegendes Konzept müssen Sie sich merken, dass eine Schnittstelle niemals irgendwelche
Implementierungen enthält. Daraus ergeben sich folgende Einschränkungen:






In einer Schnittstelle sind keinerlei Felder erlaubt, nicht einmal statische. Ein Feld ist ein
Implementierungsdetail einer Klasse oder Struktur.
Für eine Schnittstelle dürfen Sie keinerlei Konstruktoren definieren. Ein Konstruktor gilt ebenfalls
als Implementierungsdetail einer Klasse oder Struktur.
In einer Schnittstelle dürfen Sie keinen Destruktor definieren. Ein Destruktor enthält die
Anweisungen, mit denen eine Objektinstanz abgebaut wird.
Es sind keine Zugriffsmodifizierer erlaubt. Alle Methoden in einer Schnittstelle sind implizit
öffentlich.
In einer Schnittstelle dürfen Sie keine Typen (Enumerationen, Strukturen, Klassen oder
Schnittstellen) verschachteln.
Sie dürfen keine Schnittstelle von einer Struktur oder Klasse ableiten. Allerdings kann eine
Schnittstelle von einer anderen Schnittstelle erben.
Eine Schnittstelle implementieren
Um eine Schnittstelle zu implementieren, deklarieren Sie eine Klasse oder eine Struktur, die von der
Schnittstelle abgeleitet ist und die alle Methoden der Schnittstelle implementiert.
interface INamed
{
string getDescription();
void setDescription(string s);
}
public class Person : INamed
{
//Membervariablen
private string m_FirstName;
Mirco De Roni
- 45 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
private string m_LastName;
private string m_Fullname;
//Standardkonstruktor
public Person()
{
m_FirstName = "";
m_LastName = "";
m_Fullname = "";
}
//Überladener Konstruktor
public Person(string firstName, string lastName)
{
m_FirstName = firstName;
m_LastName = lastName;
m_Fullname = m_FirstName + " " + m_LastName;
}
//Methoden
string INamed.getDescription()
{
return m_Fullname;
}
public void setDescription(string fullName)
{
m_Fullname = fullName;
}
}
class Program
{
static void Main(string[] args)
{
Person p1 = new Person("Mirco", "De Roni");
Person p2 = new Person();
p2.setDescription("Victoria Muster");
INamed n1 = new Person("Jessica", "Beispiel");
Ouput(p1);
Ouput(p2);
Ouput(n1);
Console.ReadLine();
}
static void Ouput(INamed n)
{
Console.WriteLine(n.getDescription());
}
}
Wenn Sie ein Schnittstelle implementieren, müssen Sie sicherstellen, dass jede Methode genau mit der
entsprechenden Schnittstellenmethode übereinstimmt, wobei die folgenden Richtlinien zu beachten sind:




Die Namen und Rückgabetypen der Methoden müssen genau übereinstimmen.
Alle Parameter müssen exakt übereinstimmen.
Vor den Methodennamen ist der Name der Schnittstelle zu setzen. Man bezeichnet dies als
explizite Schnittstellenimplementierung.
Alle Methoden, die eine Schnittstelle implementieren, müssen öffentlich zugänglich sein. Wenn
Sie jedoch explizite Schnittstellenimplementierungen verwenden, sollten die Methoden keinen
Zugriffsmodifizierer besitzen.
Mirco De Roni
- 46 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
Besteht zwischen Schnittstellendefinition und ihrer deklarierten Implementierung irgendein Unterschied,
lässt sich die Klasse nicht kompilieren.
Vorteile expliziter Schnittstellenimplementierungen
Mehrere Schnittstellen können durchaus Methoden mit identischen Namen, Rückgabetypen und
Parametern enthalten. Implementiert eine Klasse mehrere Schnittstellen mit Methoden, die gemeinsame
Signaturen besitzen, können Sie mit expliziter Schnittstellenimplementierung Mehrdeutigkeiten bei den
Methodenimplementierungen beseitigen. Explizite Schnittstellenimplementierung gibt an, welche
Methoden in einer Klasse zu welcher Schnittstelle gehören. Darüber hinaus sind die Methoden für jede
Schnittstelle öffentlich zugänglich, jedoch nur über die Schnittstelle selbst.
Auf eine Klasse über ihre Schnittstelle verweisen
Sie können auf ein Objekt mithilfe einer Variablen verweisen, die als weiter oben in der Hierarchie
definiert ist.
INamed n1 = new Person("Jessica", "Beispiel");
Mit diesem Verfahren lassen sich Methoden definieren, die unterschiedliche Typen als Parameter
übernehmen können, sofern die Typen eine bestimmte Schnittstelle implementieren.
static void Ouput(INamed n)
{
Console.WriteLine(n.getDescription());
}
Wenn Sie auf ein Objekt über eine Schnittstelle verweisen, können Sie nur Methoden aufrufen, die über
die Schnittstelle zugänglich sind.
Mit mehreren Schnittstellen arbeiten
Eine Klasse kann höchstens eine Basisklasse besitzen, darf aber beliebig viele Schnittstellen
implementieren. Alle Methoden, die die Klasse von allen ihren Schnittstellen erbt, muss sie aber auch
implementieren.
Abstrakte Klassen
interface IVehicle
{
string Accelerate();
string Brake();
string Drive();
}
class Bicycle: IVehicle
{
string IVehicle.Accelerate()
{
return "Beschleunigen";
}
string IVehicle.Brake()
{
return "Bremsen";
}
string IVehicle.Drive()
{
return "Fahren";
}
}
class Car: IVehicle
{
string IVehicle.Accelerate()
Mirco De Roni
- 47 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
{
return "Beschleunigen";
}
string IVehicle.Brake()
{
return "Bremsen";
}
string IVehicle.Drive()
{
return "Fahren";
}
}
Doppelter Code sollte für Sie immer ein Alarmsignal sein. Überarbeiten Sie dann den Code, um die
Wiederholung zu vermeiden und die Wartungskosten zu senken. Bei dieser Umgestaltung fasst man die
gemeinsame Implementierung in einer neuen Klasse zusammen, die speziell für diesen Zweck erstellt
wird.
Um zu deklarieren, dass es nicht erlaubt ist, Instanzen einer Klasse zu erstellen, müssen Sie diese
Klasse explizit als abstrakt deklarieren. Das geschieht mit dem Schlüsselwort abstract wie im
folgenden Beispiel:
abstract class Vehicle: IVehicle
{
string IVehicle.Accelerate()
{
return "Beschleunigen";
}
string IVehicle.Brake()
{
return "Bremsen";
}
string IVehicle.Drive()
{
return "Fahren";
}
}
class Bicycle: Vehicle
{
...
}
class Car: Vehicle
{
...
}
class Program
{
static void Main(string[] args)
{
Vehicle c = new Car();
Ouput(c);
Console.ReadLine();
}
static void Ouput(IVehicle v)
{
Console.WriteLine(v.Accelerate());
Mirco De Roni
- 48 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
Console.WriteLine(v.Brake());
Console.WriteLine(v.Drive());
}
}
Versiegelte Klassen
Wenn Sie eine Klasse nicht von vornherein als Basisklasse konzipieren, ist es höchst unwahrscheinlich,
dass sie in der Praxis als Basisklasse gute Dienste leisten wird. In C# können Sie nun mit dem
Schlüsselwort sealed (versiegelt) verhindern, dass eine Klasse als Basisklasse verwendet wird. Zum
Beispiel:
sealed class Bicycle: Vehicle
{
...
}
Wenn irgendeine Klasse versucht, Bicycle als Basisklasse zu verwenden, beschwert sich der Compiler
mit einer Fehlermeldung. Eine versiegelte Klasse kann keine virtuellen Methoden deklarieren und eine
abstrakte Klasse lässt sich nicht versiegeln.
Mirco De Roni
- 49 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
14 Garbage Collection und Ressourcenverwaltung einsetzen
Der Lebenszyklus von Objekten
Ein Objekt erzeugen Sie bekanntlich mit dem Operator new. Das folgende Beispiel erstellt eine neue
Instanz der Klasse TextBox.
TextBox message = new TextBox();
Die Objekterstellung läuft in zwei Phasen ab:
1. Die new-Operation fordert einen Speicherblock vom Heap an. Auf diese Phase der
Objekterstellung haben Sie keinen Einfluss.
2. Die new-Operation konvertiert den unstrukturierten Speicher in ein Objekt – sie muss das Objekt
initialisieren. Diese Phase können Sie mit einem Konstruktor steuern.
Nachdem Sie ein Objekt erstellt haben, können Sie auf seine Member mit dem Punktoperator zugreifen.
message.Text = "Visual C#";
Wie das Erstellen läuft auch das Zerstören von Objekten in zwei Phasen ab, die ein genaues Spiegelbild
der Erstellungsphasen darstellen:
1. Die Laufzeit muss gewisse Aufräumungsarbeiten ausführen. Dies steuern Sie mit einem
Destruktor.
2. Die Laufzeit muss den Speicher, der bisher zum Objekt gehört hat, wieder an den Heap
zurückgeben. Die Zuordnung des Speichers, den das Objekt belegt hat, ist aufzuheben. Diese
Phase können Sie nicht beeinflussen.
Das Zerstören eines Objekts und die Rückgabe des Speichers an den Heap bezeichnet man als Garbage
Collection (Speicherbereinigung).
Destruktoren erstellen
Bevor ein Objekt der Speicherbereinigung zum Opfer fällt, können Sie in einem Destruktor alle
erforderlichen Aufräumungsarbeiten erledigen. Wie ein Konstruktor ist ein Destruktor eine spezielle
Methode, die aber von der Laufzeit aufgerufen wird, nachdem der letzte Verweis auf ein Objekt
verschwunden ist. Die Syntax für einen Destruktor besteht aus einer Tilde (~) und dem Name der Klasse.
Die einfache Klasse im folgenden Beispiel zählt die aktiven Instanzen, indem sie eine statische Variable
im Konstruktor inkrementiert und im Destruktor dieselbe Variable dekrementiert:
class Tally
{
private static int m_InstanceCount = 0;
public Tally()
{
m_InstanceCount++;
}
~Tally()
{
m_InstanceCount--;
}
public static int getInstanceCount()
{
return m_InstanceCount;
}
}
Mirco De Roni
- 50 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
Für Destruktoren gelten mehrere wichtige Einschränkungen:



Destruktoren lassen sich nur auf Verweistypen anwenden. In einem Werttyp beispielweise
Struktur, können Sie keinen Destruktor deklarieren.
Für einen Destruktor können Sie keinen Zugriffsmodifizierer deklarieren. Den Konstruktor rufen
Sie niemals in Ihrem eigenen Code auf – das erledigt der Garbage Collector als Instrument der
Laufzeit.
Destruktoren dürfen keine Parameter übernehmen. Auch aus diesem Grund rufen Sie den
Destruktor niemals direkt auf.
Der Compiler übersetzt den Destruktor automatisch in eine Überschreibung der Methode
object.Finalize, d.h. der Code des Destruktors
class Tally
{
~Tally()
{
...
}
}
wird übersetzt in:
class Tally
{
protected override void Finalize()
{
try {...}
finally { base.Finalize(); }
}
}
Warum wird der Garbage Collector verwendet?
 Sie vergessen ein Objekt zu zerstören. Damit wird der Destruktor des Objekts nicht aufgerufen,
die Aufräumungsarbeiten finden nicht statt und der Speicher geht nicht an den Heap zurück.
Dadurch steht bald kein Speicher mehr zur Verfügung.
 Sie versuchen, ein aktives Objekt zu zerstören. Wie Sie wissen, erfolgt der Zugriff auf Objekte
über Verweise. Wenn eine Klasse einen Verweis auf ein zerstörtes Objekt enthält, handelt es
sich um einen ungültigen Verweis. Letztlich verweist dieser ungültige Verweis auf nicht
verwendeten Speicher oder ein vollkommen anderes Objekt im selben Speicherbereich.
 Sie versuchen, dasselbe Objekt mehrmals zu zerstören. Abhängig vom Code im Destruktor
könnte das katastrophale Auswirkungen haben.
Derartige Probleme sind einfach inakzeptabel in einer Sprache wie C#, bei der Stabilität und Sicherheit
ganz oben auf der Liste der Entwurfsziele stehen. Deshalb ist der Garbage Collector dafür zuständig, die
Objekte zu zerstören und garantiert dabei Folgendes:



Er zerstört jedes Objekt und ruft seinen Destruktor auf. Wenn ein Programm endet, zerstört er
alle noch ausstehende Objekte.
Er zerstört jedes Objekt genau einmal.
Er zerstört jedes Objekt erst, wenn es unerreichbar wird, d.h. wenn sich keine Verweise mehr auf
das Objekt beziehen.
Diese Garantien sind enorm nützlich und befreien den Programmierer von lästigen Verwaltungsarbeiten.
Der Programmierer kann sich auf die eigentliche Programmlogik konzentrieren, was sich günstig auf die
Produktivität auswirkt.
Wie funktioniert der Garbage Collector?
Der Garbage Collector läuft in einem eigenen Thread und kann nur zu bestimmten Zeitpunkten
ausgeführt werden. Während er aktiv ist, halten andere Threads, die in Ihrer Anwendung laufen,
vorübergehend an. Das geschieht deshalb, weil der Garbage Collector gegebenenfalls Objekte
Mirco De Roni
- 51 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
verschieben und Objektverweise aktualisieren muss. Das geht nicht mit Objekten, die ein Programm
gerade verwendet. Der Garbage Collector unternimmt folgende Schritte:
1. Er erstellt eine Tabelle aller erreichbaren Objekte. Dazu verfolgt er wiederholt Verweisfelder
innerhalb von Objekten. Der Garbage Collector erstellt diese Tabelle sehr sorgfältig und
gewährleistet, dass zirkuläre Verweise nicht zu einer unendlichen Rekursion führen. Jedes
Objekt, das nicht in dieser Tabelle erscheint, gilt als unerreichbar.
2. Der Garbage Collector prüft, ob die unerreichbaren Objekte einen Destruktor besitzen, der
ausgeführt werden muss. Jedes unerreichbare Objekt, das eine Finalisierung verlangt, wird in
eine spezielle Warteschlange gestellt, die so genannte Finalizer-Warteschlange.
3. Er hebt die Speicherreservierung der unerreichbaren Objekte auf. Dazu verschiebt er die
erreichbaren Objekte im Heap nach unten, defragmentiert somit den Heap und gibt den Speicher
an der Spitze des Heaps frei. Wenn der Garbage Collector ein erreichbares Objekt verschiebt,
aktualisiert er auch alle Verweise auf das Objekt.
4. Zu diesem Zeitpunkt lässt der Garbage Collector die Fortsetzung anderer Threads zu.
5. In einem separaten Thread finalisiert der Garbage Collector die unerreichbaren Objekte.
Ressourcenverwaltung
Knappe Ressourcen müssen wieder freigegeben werden und zwar so schnell wie möglich. In diesen
Situationen haben Sie nur die Option, die Ressourcen in eigener Regie freizugeben. Zu diesem Zweck
gibt es Freigabemethoden. Besitzt eine Klasse eine Freigabemethode, können Sie sie explizit aufrufen
und dabei steuern, wann die Ressource freigegeben wird.
Freigabemethoden
TextReader reader = new StreamReader(fullPathname);
string line;
while ((line = reader.ReadLine()) != null)
{
Console.WriteLine(line);
}
reader.Close();
Ausnahmesichere Freigabe von Ressourcen
TextReader reader = new StreamReader(fullPathname);
try
{
string line;
while ((line = reader.ReadLine()) != null)
{
Console.WriteLine(line);
}
}
finally
{
reader.Close();
}
Allerdings hat eine derartige Variante mehrere Nachteile und ist damit keineswegs optimal:




Wenn Sie mehr als eine Ressource freigeben müssen, wird das Verfahren schnell unhandlich.
In manchen Fällen müssen Sie den Code modifizieren.
Die Lösung lässt sich nicht abstrahieren. Das heisst, sie ist schwer verständlich und man muss
den Code an allen Stellen wiederholen, wo diese Funktionalität notwendig ist.
Der Verweis auf die Ressource bleibt auch nach dem finally-Block weiterhin im
Gültigkeitsbereich.
Die im Folgenden beschriebene using-Anweisung löst all diese Probleme.
Mirco De Roni
- 52 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
Die using-Anweisung
Die using-Anweisung stellt einen sauberen Mechanismus bereit, um die Lebenszeit von Ressourcen zu
steuern. Man kann ein Objekt erzeugen und dieses Objekt wird zerstört, wenn der Block der usingAnweisung endet.
using (TextReader reader = new StreamReader(fullPathname))
{
string line;
while ((line = reader.ReadLine()) != null)
{
Console.WriteLine(line);
}
}
Mit einer using-Anweisung können Sie auf saubere, ausnahmesichere und robuste Art sicherstellen,
dass eine Ressource immer automatisch freigegeben wird. Das löst alle Probleme, die bei der manuellen
try/finally-Variante existieren. Jetzt verfügen Sie über eine Lösung, die




sich skalieren lässt, wenn Sie mehrere Ressourcen freigeben müssen,
die Logik des Programmcodes nicht stört,
das Problem abstrahiert und wiederholten Code vermeidet,
robust ist. Die innerhalb der using-Anweisung deklarierte Variable können Sie nicht mehr
verwenden, nachdem die using-Anweisung beendet ist, weil die Variable nicht mehr gültig ist –
andernfalls erhalten Sie eine Fehlermeldung des Compilers.
Mirco De Roni
- 53 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
15 Eigenschaften implementieren, um auf Attribute zuzugreifen
Was sind Eigenschaften?
Eine Eigenschaft ist eine Kreuzung aus Feld und Methode – sie sieht wie ein Feld aus, agiert aber wie
eine Methode. Auf eine Eigenschaft greift man mit genau der gleichen Syntax wie auf ein Feld zu.
Allerdings übersetzt der Compiler diese feldartige Syntax automatisch in Aufrufe von Accessormethoden.
Eine Eigenschaftendeklaration sieht folgendermassen aus:
ZugriffsModifizierer Typ EigenschaftenName
{
get
{
//Code für Lesemethode
}
set
{
//Code für Schreibmethode
}
}
Eine Eigenschaft kann zwei Codeblöcke enthalten, die mit den Schlüsselwörtern get und set beginnen.
Die Anweisungen im get-Block werden ausgeführt, wenn die Eigenschaft gelesen wird. Der set-Block
enthält Anweisungen, die beim Schreiben der Eigenschaft ausgeführt werden. Der Typ der Eigenschaft
spezifiziert den Typ der Daten, die sich mit den get- und set-Accessoren lesen und schreiben lassen.
Das nächste Codefragment zeigt die Struktur ScreenPosition in einer neuen Fassung, die
Eigenschaften verwendet. Beachten Sie dabei folgende Konventionen:


Die Kleinbuchstaben x und y bezeichnen private Felder.
Die Grossbuchstaben X und Y bezeichnen öffentliche Eigenschaften.
Tipp
Die Benennung der Felder und Eigenschaften folgt den Konventionen von Microsoft Visual C# für
öffentliche und private Member: Öffentliche Felder und Eigenschaften sollten mit einem Grossbuchstaben
beginnen, private Felder und Eigenschaften mit einem Kleinbuchstaben.
struct ScreenPosition
{
private int x, y;
private static int rangeCheckedX(int x)
{
return x;
}
private static int rangeCheckedY(int y)
{
return y;
}
public ScreenPosition(int X, int Y)
{
this.x = rangeCheckedX(X);
this.y = rangeCheckedY(Y);
}
public int X
{
get { return this.x; }
set { this.x = rangeCheckedX(value); }
}
Mirco De Roni
- 54 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
public int Y
{
get { return this.y; }
set { this.y = rangeCheckedY(value); }
}
}
Eigenschaften verwenden
Wenn Sie eine Eigenschaft in einem Ausdruck verwenden, geschieht das entweder in einem Lesekontext
oder in einem Schreibkontext.
static void Main(string[] args)
{
ScreenPosition position = new ScreenPosition(0, 0);
int xPos = position.X;
//ruft position.X get auf
int yPos = position.Y;
//ruft position.Y get auf
Console.WriteLine("Position");
Console.WriteLine("X: " + xPos + "\nY: " + yPos);
}
Schreibgeschützte Eigenschaften
Wenn Sie eine Eigenschaft deklarieren, die lediglich einen get-Accessor enthält, können Sie diese
Eigenschaft nur in einem Lesekontext verwenden.
struct ScreenPosition
{
...
public int X
{
get { return this.x; }
}
}
Lesegeschützte Eigenschaften
Dementsprechend können Sie auch eine Eigenschaft erstellen, die lediglich einen set-Accessor enthält.
In diesem Fall lässt sich die Eigenschaft nur in einem Schreibkontext verwenden.
struct ScreenPosition
{
...
public int X
{
set { this.x = rangeCheckedX(value); }
}
}
Zugriffsmodifizierer bei Eigenschaften
Den Zugriff auf eine Eigenschaft (öffentlich, privat oder geschützt) legen Sie fest, wenn Sie die
Eigenschaft deklarieren. Allerdings ist es möglich, unterschiedliche Zugriffsmodifizierer für get- und setAccessoren anzugeben.
struct ScreenPosition
{
...
public int X
{
get { return this.x; }
private set { this.x = rangeCheckedX(value); }
}
public int Y
Mirco De Roni
- 55 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
{
get { return this.y; }
private set { this.y = rangeCheckedY(value); }
}
}
Einschränkungen von Eigenschaften verstehen
Eigenschaften weisen viele Ähnlichkeiten mit Feldern auf. Allerdings sind es keine echten Felder uns so
gelten auch einige Einschränkungen für Eigenschaften:





Einen Wert können Sie über eine Eigenschaft einer Struktur oder Klasse nur zuweisen, nachdem
die Struktur oder Klasse initialisiert wurde.
Eine Eigenschaft können Sie nicht als ref- oder out-Argument verwenden.
Eine Eigenschaft darf höchstens einen get-Accessor und einen set-Accessor enthalten. Andere
Methoden, Felder oder Eigenschaften sind in einer Eigenschaft nicht zulässig.
Die get- und set-Accessoren dürfen keine Parameter übernehmen. Die zuzuweisenden Daten
werden an den set-Accessor automatisch mithilfe der Variablen value übergeben.
Eigenschaften können Sie nicht als const deklarieren.
Schnittstelleneigenschaften deklarieren
In Schnittstellen können Sie ausser Methoden auch Eigenschaften spezifizieren. Dazu verwenden Sie die
Schlüsselwörter get und/oder set, ersetzen aber den Körper des get- oder set-Accessors durch ein
Semikolon. Zum Beispiel:
interface IScreenPosition
{
int X { get; set; }
int Y { get; set; }
}
Jede Klasse oder Struktur, die diese Schnittstelle implementiert, muss dann auch die Eigenschaften X
und Y mit den get- und set-Accessoren implementieren. Auch dazu wieder ein Beispiel:
struct ScreenPosition: IScreenPosition
{
public int X
{
get { ... }
set { ... }
}
public int Y
{
get { ... }
set { ... }
}
}
Mirco De Roni
- 56 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
16 Delegaten und Ereignisse
Delegaten deklarieren und verwenden
Ein Delegat ist ein Zeiger auf eine Methode und Sie rufen ihn in der gleichen Weise wie eine Methode
auf. Wenn Sie allerdings einen Delegaten aufrufen, führt die Laufzeit tatsächlich die Methode aus, auf die
der Delegat verweist. Diese Methode wiederum können Sie dynamisch ändern, sodass der Code, der
einen Delegaten aufruft, bei jedem Aufruf durchaus eine andere Methode ausführen könnte.
Hinweis
Die Abkürzung API bedeutet Application Programming Interface – Anwendungsprogrammierschnittstelle.
Es handelt sich um eine Methode oder einen Satz von Methoden, die ein bestimmter Teil von Software
verfügbar macht, damit Sie diese Software steuern können. Microsoft .NET Framework können Sie sich
als Satz von APIs vorstellen, da Sie über dessen Methoden die .NET Common Language Runtime (CLR)
und das Betriebssystem Microsoft Windows steuern können.
Einen Delegaten deklarieren Sie wie folgt:
delegate void Tick(int h, int m, int s);
Beachten Sie die folgenden Punkte:


Geben Sie das Schlüsselwort delegate an, wenn Sie einen Delegaten deklarieren.
Ein Delegat definiert die Gestalt der Methoden, auf die er verweisen kann. Dazu spezifizieren Sie
den Rückgabetyp und gegebenenfalls die Parameter.
Nachdem Sie den Delegaten definiert haben, können Sie eine Instanz erzeugen und sie mit dem
Verbundzuweisungsoperator += auf eine passende Methode verweisen lassen.
class Ticker
{
public delegate void Tick(int h, int m, int s);
private Tick tickers;
public Ticker()
{
}
public void Add(Tick newMethod)
{
this.tickers += newMethod;
}
}
Sie können mit dem Schlüsselwort new ausserdem auch einen Delegaten explizit mit einer bestimmten
Methode initialisieren:
this.tickers = new Tick(newMethod);
Die Methode rufen Sie folgendermassen über den Delegaten auf:
this.tickers();
Einen Delegaten rufen Sie mit der gleichen Syntax wie eine Methode auf. Übernimmt die Methode, auf
die der Delegat verweist, irgendwelche Parameter, geben Sie diese in den Klammern mit an.
Ein Delegat bietet vor allem den Vorteil, dass er auf mehr als eine Methode verweisen kann. Diese
Methoden fügen Sie dem Delegaten ganz einfach mit dem Operator += hinzu.
Mirco De Roni
- 57 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
Mit dem Verbundzuweisungsoperator -= können Sie auch eine Methode aus einem Delegaten entfernen:
public void Remove(Tick oldMethod)
{
this.tickers -= oldMethod;
}
Benachrichtigungen mit Ereignissen realisieren
In .NET Framework ist es mit Ereignissen möglich, wichtige Aktionen zu definieren und abzufangen sowie
einen Delegaten damit zu beauftragen, sich der Situation anzunehmen. Viele Klassen im .NETFramework machen Ereignisse verfügbar.
Ein Ereignis deklarieren
Ein Ereignis deklarieren Sie in einer Klasse, die als Ereignisquelle fungieren soll. Als Ereignisquelle
kommt normalerweise eine Klasse infrage, die ihre Umgebung überwacht und ein Ereignis auslöst,
sobald etwas Bedeutsames passiert.
Ein Ereignis deklarieren Sie in ähnlicher Form wie ein Feld. Da jedoch Ereignisse für die Verwendung mit
Delegaten konzipiert sind, muss der Typ eines Ereignisses ein Delegat sein. Zudem ist vor die
Deklaration eines Ereignisses das Schlüsselwort event zu setzen.
Die Syntax für die Deklaration eines Ereignisses sieht folgendermassen aus:
event delegatTypName ereignisName
public delegate void Tick(int h, int m, int s);
public event Tick tick;
Ein Ereignis abonnieren
Wie Delegaten verfügen Ereignisse über einen Operator +=. Mit diesem Operator können Sie ein
Ereignis abonnieren.
class Ticker
{
public delegate void Tick(int h, int m, int s);
public event Tick tick;
...
}
private Ticker ticker = new Ticker();
ticker.tick += this.RefreshTime;
private void RefreshTime(int hh, int mm, int ss)
{
this.txtBoxDisplay.Text = string.Format("{0:D2}:{1:D2}:{2:D2}", hh, mm, ss);
}
Das Abonnement eines Ereignisses kündigen
Der Aufruf des Operators -= entfernt die Methode aus der internen Delegatenauflistung des Ereignisses –
das Ereignis wird gekündigt.
Ein Ereignis auslösen
Ein Ereignis lässt sich genau wie ein Delegat auslösen, indem man es wie eine Methode aufruft. Wenn
Sie ein Ereignis auslösen, werden nacheinander alle gebundenen Delegaten aufgerufen.
class Ticker
{
public delegate void Tick(int h, int m, int s);
public event Tick tick;
Mirco De Roni
- 58 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
private void Notify(int hours, int minutes, int seconds)
{
if (this.tick != null)
{
this.tick(hours, minutes, seconds);
}
}
}
Mirco De Roni
- 59 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
17 Einführung in Generics
Eine generische Klasse erstellen
C# stellt Generics bereit, um die notwendige Typumwandlung zu beseitigen, die Typsicherheit zu
verbessern, den Umfang des erforderlichen Boxings zu verringern und es sicherer zu machen,
verallgemeinerte Klasen und Methoden zu erstellen. Generische Klassen und Methoden übernehmen
Typparameter. Diese spezifizieren den Typ der Objekte, auf denen sie arbeiten. Die .NET FrameworkKlassenbibliothek umfasst generische Versionen vieler Auflistungsklassen und Schnittstellen im
Namespace System.Collections.Generic.
Die Theorie der binären Bäume
Ein binärer Baum ist eine rekursive Datenstruktur, die entweder leer sein kann oder drei Elemente
umfasst: bestimmte Daten, die man normalerweise als Knoten bezeichnet und zwei Teilbäume, die selbst
binäre Bäume sind. Es hat sich eingebürgert, die beiden Teilbäume als linken und rechten Teilbaum zu
bezeichnen.
Eine Binärbaum-Klasse mit Generics erstellen
public class Tree<TItem> where TItem : IComparable<TItem>
{
public Tree(TItem nodeValue)
{
this.NodeData = nodeValue;
this.LeftTree = null;
this.RightTree = null;
}
public void Insert(TItem newItem)
{
TItem currentNodeValue = this.NodeData;
if (currentNodeValue.CompareTo(newItem) > 0)
{
if (this.LeftTree == null)
{
this.LeftTree = new Tree<TItem>(newItem);
}
else
{
this.LeftTree.Insert(newItem);
}
}
else
{
if (this.RightTree == null)
{
this.RightTree = new Tree<TItem>(newItem);
}
else
{
this.RightTree.Insert(newItem);
}
}
}
public void WalkTree()
{
if (this.LeftTree != null)
{
this.LeftTree.WalkTree();
}
Console.WriteLine(this.NodeData.ToString());
Mirco De Roni
- 60 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
if (this.RightTree != null)
{
this.RightTree.WalkTree();
}
}
public TItem NodeData { get; set; }
public Tree<TItem> LeftTree { get; set; }
public Tree<TItem> RightTree { get; set; }
}
class Program
{
static void Main(string[] args)
{
Tree<int> tree1 = new Tree<int>(10);
tree1.Insert(5);
tree1.Insert(11);
tree1.Insert(5);
tree1.Insert(-12);
tree1.Insert(15);
tree1.Insert(0);
tree1.Insert(14);
tree1.Insert(-8);
tree1.Insert(10);
tree1.Insert(8);
tree1.Insert(8);
tree1.WalkTree();
Tree<string> tree2 = new Tree<string>("Hello");
tree2.Insert("World");
tree2.Insert("How");
tree2.Insert("Are");
tree2.Insert("You");
tree2.Insert("Today");
tree2.Insert("I");
tree2.Insert("Hope");
tree2.Insert("You");
tree2.Insert("Are");
tree2.Insert("Feeling");
tree2.Insert("Well");
tree2.Insert("!");
tree2.WalkTree();
}
}
Mirco De Roni
- 61 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
18 Speicherinterne Daten mit Abfrageausdrücken abrufen
Was ist LINQ?
Die Designer von LINQ (Language Integrated Query) haben sich an dem Konzept orientiert, nach dem
relationale Datenbankmanagementsysteme wie zum Beispiel Microsoft SQL Server die für die Abfrage
der Datenbank verwendete Sprache von der internen Darstellung der Daten in der Datenbank trennen.
Entwickler, die auf eine SQL Server-Datenbank zugreifen, richten SQL (Structured Query Language)Anweisungen an das Datenbankmanagementsystem. SQL beschreibt auf einer höheren Ebene die
Daten, die der Entwickler abrufen möchte, gibt aber nicht genau an, wie das
Datenbankmanagementsystem diese Daten abrufen soll. Das sind Details, die das
Datenbankmanagementsystem selbst steuert.
Syntax und Semantik von LINQ erinnern stark an SQL und bieten viele der gleichen Vorteile. Die
zugrunde liegende Struktur der abzufragenden Daten lässt sich ändern, ohne den Code ändern zu
müssen, der die eigentlichen Abfragen ausführt. Doch auch wenn LINQ ähnlich wie SQL aussieht, ist es
weit flexibler und beherrscht ein breiteres Spektrum an logischen Datenstrukturen. Zum Beispiel kann
LINQ mit hierarchisch organisierten Daten umgehen, wie sie beispielsweise in einem XML-Dokument zu
finden sind.
LINQ in einer C#-Anwendung einsetzen
class Employee
{
public int m_EmployeeID;
public string m_FirstName;
public string m_LastName;
public string m_CompanyName;
public string m_Department;
public override string ToString()
{
return String.Format("{0} {1}", this.m_FirstName, this.m_LastName);
}
}
class Address
{
public int m_fk_EmployeeID;
public string m_City;
}
static void Main(string[] args)
{
var employees = new[]
{
new Employee { m_EmployeeID = 1, m_FirstName = "Mirco", m_LastName =
"De Roni", m_CompanyName = "Informatik GmbH", m_Department =
"Entwicklung" },
new Employee { m_EmployeeID = 2, m_FirstName = "Victoria", m_LastName =
"Muster", m_CompanyName = "Schindler Informatik AG", m_Department =
"Entwicklung" },
new Employee { m_EmployeeID = 3, m_FirstName = "Simon", m_LastName =
"Birrer", m_CompanyName = "Informatik GmbH", m_Department =
"Entwicklung" },
new Employee { m_EmployeeID = 4, m_FirstName = "Francesco", m_LastName
= "Example", m_CompanyName = "Digitec", m_Department = "Verkauf" },
new Employee { m_EmployeeID = 5, m_FirstName = "Jessica", m_LastName =
"Beispiel", m_CompanyName = "Bike Store", m_Department = "IT" },
new Employee { m_EmployeeID = 6, m_FirstName = "Hans", m_LastName =
"Muster", m_CompanyName = "Informatik GmbH", m_Department =
"Support" },
new Employee { m_EmployeeID = 7, m_FirstName = "Eric", m_LastName =
"Long", m_CompanyName = "Bike Store", m_Department = "Support" },
new Employee { m_EmployeeID = 8, m_FirstName = "Katy", m_LastName =
Mirco De Roni
- 62 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
"Black",
m_CompanyName = "PC Store", m_Department = "Marketing" },
};
var adresses = new[]
{
new Address { m_fk_EmployeeID = 1, m_City = "Luzern" },
new Address { m_fk_EmployeeID = 5, m_City = "Bern" },
};
Console.WriteLine("------------------------------------");
Console.WriteLine("Liste der Abteilungen");
Console.WriteLine("------------------------------------");
var departments = (from e in employees
orderby e.m_Department ascending
select e.m_Department).Distinct();
foreach (var aDepartment in departments)
{
Console.WriteLine("Abteilung: {0}", aDepartment);
}
int numberOfDepartments = (from e in employees
select e.m_Department).Distinct().Count();
Console.WriteLine("\nAnzahl der Abteilungen: {0}", numberOfDepartments);
Console.WriteLine("\n------------------------------------");
Console.WriteLine("Mitarbeiter in der Entwicklung-Abteilung");
Console.WriteLine("------------------------------------");
var devEmployees = from e in employees
where String.Equals(e.m_Department, "Entwicklung")
select e;
foreach (var anEmployee in devEmployees)
{
Console.WriteLine(anEmployee);
}
Console.WriteLine("\n------------------------------------");
Console.WriteLine("Alle Mitarbeiter gruppiert nach Abteilung");
Console.WriteLine("------------------------------------");
var employeesGroupedByDepartment = from e in employees
group e by e.m_Department;
foreach (var aDepartment in employeesGroupedByDepartment)
{
Console.WriteLine("{0}", aDepartment.Key);
foreach (var anEmployee in aDepartment)
{
Console.WriteLine("\t{0} {1}", anEmployee.m_FirstName,
anEmployee.m_LastName);
}
}
Console.WriteLine("\n------------------------------------");
Console.WriteLine("Liste der Firmen");
Console.WriteLine("------------------------------------");
var companies = (from e in employees select e.m_CompanyName).Distinct();
foreach (var aCompany in companies)
{
Console.WriteLine("Firma: {0}", aCompany);
}
int numberOfCompanies = (from e in employees
select e.m_CompanyName).Distinct().Count();
Mirco De Roni
- 63 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
Console.WriteLine("\nAnzahl der Firmen: {0}", numberOfCompanies);
Console.WriteLine("\n------------------------------------");
Console.WriteLine("Alle Mitarbeiter gruppiert nach Firma");
Console.WriteLine("------------------------------------");
var employeesGroupedByCompany = from e in employees
group e by e.m_CompanyName;
foreach (var aCompany in employeesGroupedByCompany)
{
Console.WriteLine("{0}", aCompany.Key);
foreach (var anEmployee in aCompany)
{
Console.WriteLine("\t{0} {1}", anEmployee.m_FirstName,
anEmployee.m_LastName);
}
}
Console.WriteLine("\n------------------------------------");
Console.WriteLine("JOIN");
Console.WriteLine("------------------------------------");
var join = from e in employees
join a in adresses
on e.m_EmployeeID equals a.m_fk_EmployeeID
select new { e.m_FirstName, e.m_LastName, a.m_City };
foreach (var anEmployee in join)
{
Console.WriteLine("{0} {1}, {2}", anEmployee.m_FirstName,
anEmployee.m_LastName, anEmployee.m_City);
}
Console.ReadLine();
}
Daten auswählen
Die Daten wählen Sie mit dem Operator select aus.
var companies = (from e in employees select e.m_CompanyName).Distinct();
foreach (var aCompany in companies)
{
Console.WriteLine("Firma: {0}", aCompany);
}
Daten filtern
Die Daten filtern Sie mit dem where-Operator.
var devEmployees = from e in employees
where String.Equals(e.m_Department, "Entwicklung")
select e;
foreach (var anEmployee in devEmployees)
{
Console.WriteLine(anEmployee);
}
Daten sortieren, gruppieren und zusammenfassen
Die Daten sortieren Sie wie folgt mit dem Operator orderby:
var departments = (from e in employees
orderby e.m_Department ascending
select e.m_Department).Distinct();
foreach (var aDepartment in departments)
{
Mirco De Roni
- 64 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
Console.WriteLine("Abteilung: {0}", aDepartment);
}
Mit dem Operator group gruppieren Sie die Daten:
var employeesGroupedByDepartment = from e in employees
group e by e.m_Department;
foreach (var aDepartment in employeesGroupedByDepartment)
{
Console.WriteLine("{0}", aDepartment.Key);
foreach (var anEmployee in aDepartment)
{
Console.WriteLine("\t{0} {1}", anEmployee.m_FirstName,
anEmployee.m_LastName);
}
}
Auf die Ergebnisse der select-Methode können Sie viele der Zusammenfassungsmethoden wie Count,
Max und Min direkt anwenden.
int numberOfDepartments = (from e in employees
select e.m_Department).Distinct().Count();
Console.WriteLine("Anzahl der Abteilungen: {0}", numberOfDepartments);
Daten verknüpfen
Genau wie SQL ist es mit LINQ möglich, mehrere Mengen von Daten miteinander über einen oder
mehrere gemeinsame Schlüsselfelder zu verknüpfen.
Mit dem Operator join lassen sich zwei Auflistungen über einen gemeinsamen Schlüssel verknüpfen.
var join = from e in employees
join a in adresses
on e.m_EmployeeID equals a.m_fk_EmployeeID
select new { e.m_FirstName, e.m_LastName, a.m_City };
foreach (var anEmployee in join)
{
Console.WriteLine("{0} {1}, {2}", anEmployee.m_FirstName,
anEmployee.m_LastName, anEmployee.m_City);
}
Mirco De Roni
- 65 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
19 Überladen von Operatoren
Operatoren verstehen
Mit Operatoren kombinieren Sie Operanden in Ausdrücken. Jeder Operator besitzt seine eigene
Semantik abhängig vom Typ, mit dem er arbeitet.
Jedes Operatorensymbol besitzt einen bestimmten Vorrang. Zum Beispiel hat der Operator * einen
höheren Vorrang als der Operator +. Das bedeutet, dass der Ausdruck a + b * c gleichbedeutend mit a +
(b * c) ist.
Ausserdem ist jedem Operatorensymbol eine Orientierung oder Assoziativität zugeordnet, die
entscheidet, ob der Operator von links nach rechts oder von rechts nach links auswertet.
Ein unärer Operator wirkt auf nur einen Operanden. Zu dieser Kategorie gehört der Inkrementoperator
(++).
Ein binärer Operator – zum Beispiel der Multiplikationsoperator (*) – verknüpft zwei Operanden.
Operatoreneinschränkungen
Es gelten folgende Regeln:





Vorrang und Orientierung eines Operators lassen sich nicht ändern. Der Vorrang und die
Orientierung basieren auf dem Operatorsymbol und nicht auf dem Typ, auf den das
Operatorsymbol angewendet wird.
Die Anzahl der Operanden für einen Operator lässt sich nicht ändern.
Sie können keine neuen Operatorensymbole erfinden. Beispielweise ist es nicht möglich, ein
neues Operatorsymbol wie zum Beispiel ** für die Potenzierung einzuführen. In solchen Fällen
müssen Sie eine Methode erstellen.
Die Bedeutung der Operatoren in Verbindung mit integrierten Typen lässt sich nicht ändern.
Bestimmte Operatorsymbole dürfen nicht überladen werden. Das betrifft beispielweise den
Punktoperator.
Überladene Operatoren
Um das Verhalten eines eigenen Operators zu definieren, müssen Sie einen ausgewählten Operator
überladen. Dazu verwenden Sie eine methodenähnliche Syntax mit einem Rückgabetyp und Parametern.
struct Hour
{
private int value;
public Hour(int initialValue)
{
this.value = initialValue;
}
public static Hour operator+(Hour lhs, Hour rhs)
{
return new Hour(lhs.value + rhs.value);
}
}
Beachten Sie folgende Punkte:



Der Operator ist öffentlich. Alle Operatoren müssen öffentlich sein.
Der Operator ist statisch. Alle Operatoren müssen statisch sein. Operatoren sind niemals
polymorph und dürfen nicht die Modifizierer virtual, abstract, override und sealed
verwenden.
Ein binärer Operator besitzt zwei explizite Argumente, ein unärer Operator ein explizites
Argument.
Mirco De Roni
- 66 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
Hour Example(Hour a, Hour b)
{
return a + b;
}
Verbundzuweisungen verstehen
Ein Verbundzuweisungsoperator wird immer in Bezug auf seinen zugeordneten Operator ausgewertet.
Mit anderen Worten wird die Anweisung
a += b;
automatisch als
a = a + b;
ausgewertet.
Mirco De Roni
- 67 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
20 Einführung in Windows Presentation Foundation
Eine WPF-Anwendung erstellen
Um eine WPF-Anwendung zu erstellen, klicken Sie in Visual Studio auf das Menü Datei  Neu 
Projekt…. Anschliessend wählen Sie den Eintrag WPF-Anwendung.
Die XAML-Definition des Formulars sieht folgendermassen aus:
<Window x:Class="Einstieg.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
</Grid>
</Window>
Das Attribut class spezifiziert den vollqualifizierten Namen der Klasse, die das Formular implementiert.
Die Vorlage WPF-Anwendung verwendet den Namen der Anwendung als Standardnamespace für
Formulare. Die xmlns-Attribute geben die XML-Namespaces an, die die von WPF verwendeten
Schemas definieren. Alle Steuerelemente und anderen Elemente, die Sie in eine WPF-Anwendung
einbinden können, besitzen Definitionen in diesen Namespaces. Das Attribut Title spezifiziert den Text,
der in der Titelleiste des Formulars erscheint. Mit den Attributen Height und Width werden die
Standardwerte für Höhe und Breite des Formulars angegeben. Diese Werte können Sie entweder im
XAML-Bereich oder im Eigenschaftenfenster dynamisch mithilfe von C#-Code ändern, der bei aktivem
Formular ausgeführt wird.
Konnektoren
Ankerpunkte
Tipp
Im Fenster Eigenschaften können Sie viele Eigenschaften eines Steuerelements, wie zum Beispiel
Margin, jedoch nicht alle Eigenschaften festlegen. Und manchmal ist es einfacher, die Werte direkt im
XAML-Bereich einzutippen, sofern Sie dabei sorgfältig vorgehen.
Hinweis
Wenn Sie die Eigenschaften Width und Height des Buttons-Steuerelements nicht festlegen, nimmt die
Schaltfläche das gesamte Formular ein.
Ein Panel ist ein Steuerelement, das als Container für andere Steuerelemente fungiert und bestimmt, wie
sie relativ zueinander angeordnet werden. Das Grid-Steuerelement ist ein Beispiel für ein PanelSteuerelement.
Mirco De Roni
- 68 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
Mit WPF können Sie die Art und Weise beeinflussen, in der sich Steuerelemente wie Schaltflächen,
Textfelder und Labels selbst auf einem Formular darstellen.
Steuerelemente in das Formular aufnehmen
Die WPF-Bibliothek enthält eine umfangreiche Palette von Steuerelementen. Die Aufgaben vieler
Steuerelemente wie TextBox, ListBox, CheckBox oder ComboBox sind ohne weiteres klar, während
leistungsfähigere Steuerelemente vielleicht nicht so bekannt sind.
Alle verfügbaren Steuerelemente befinden sich in der Toolbox. Wenn Sie ein neues Element auf dem
Formular darstellen wollen, ziehen Sie einfach ein Element aus der Toolbox auf das Formular. Danach
können Sie das Element an die gewünschte Position verschieben und die Grösse anpassen.
Ereignisse in einem WPF-Formular behandeln
Als Entwickler haben Sie die Aufgabe, die Ereignisse abzufangen, die für Ihre Anwendung relevant sind.
Mit entsprechendem Code reagieren Sie auf diese Ereignisse. Ein bekanntes Beispiel ist das ButtonSteuerelement (Schaltfläche).
private void btnFinish_Click(object sender, RoutedEventArgs e)
{
Close();
}
Der XAML-Code sieht dann wie folgt aus:
<Button Height="23" HorizontalAlignment="Right" Margin="0,44,36,0"
Name="btnFinish" VerticalAlignment="Top" Width="75"
Click="btnFinish_Click">Beenden</Button>
Mirco De Roni
- 69 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
21 Mit Menüs und Dialogfeldern arbeiten
Richtlinien für Menüs
In den meisten Windows-Anwendungen befinden sich bestimmte Elemente in der Menüleiste immer an
der gleichen Stelle und der Inhalt dieser Menüs ist in der Regel vorhersehbar.
Auch die Reihenfolge der Befehle in den Menüs ist meistens identisch. So ist der Befehl Beenden in der
Regel der letzte Befehl im Menü Datei. Neben den Standardbefehlen können sich im Menü Datei auch
anwendungsspezifische Befehle befinden.
Menüs und Menüereignisse
WPF stellt das Steuerelement Menu als Container für Menübefehle bereit. Das Steuerelement Menu
realisiert eine grundsätzliche Shell, mit der sich Menüs definieren lassen. Wie die meisten Aspekte von
WPF ist das Steuerelement Menu sehr flexibel, sodass Sie eine Menüstruktur mit nahezu jedem WPFSteuerelementtyp definieren können. Menüs lassen sich mit dem XAML-Bereich in der Entwurfsansicht
definieren und es ist auch möglich, Menüs zur Laufzeit mit Microsoft Visual C#-Code zu konstruieren.
Um ein neues Menü darzustellen, ziehen Sie aus der Toolbox im Abschnitt Steuerelemente ein MenuSteuerelement auf das Formular. Anschliessend modifizieren Sie im XAML-Bereich die Definition des
Menu-Steuerelements und fügen dann die MenuItem-Elemente hinzu. Als letztes fügen Sie dem Menü
Neu noch ein Bild hinzu. Hierfür müssen Sie im Projektmappen-Explorer mit der rechten Maustaste auf
das Projekt klicken und wählen Hinzufügen  Vorhandenes Element…. Im Dialog Vorhandenes
Element hinzufügen navigieren Sie zu einer Bilddatei und klicken dann auf Hinzufügen.
<Menu Height="22" Name="menu1" VerticalAlignment="Top">
<MenuItem Header="Datei">
<MenuItem Header="Neues Mitglied" Name="mnuNewMember"
Click="mnuNewMember_Click">
<MenuItem.Icon>
<Image Source="user.png" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Öffnen" Name="mnuOpen" />
<Separator />
<MenuItem Header="Mitgliedsdaten speichern" Name="mnuSaveMember"
Click="mnuSaveMember_Click" IsEnabled="False">
<MenuItem.Icon>
<Image Source="save.png" />
</MenuItem.Icon>
</MenuItem>
<Separator />
<MenuItem Header="Beenden" Name="mnuFinish" Click="mnuFinish_Click" />
</MenuItem>
<MenuItem Header="Hilfe"></MenuItem>
</Menu>
private void mnuFinish_Click(object sender, RoutedEventArgs e)
{
Close();
}
Mirco De Roni
- 70 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
Kontextmenüs
Viele Windows-Anwendungen arbeiten mit Popup-Menüs, die erscheinen, wenn der Benutzer ein
Formular oder ein Steuerelement mit der rechten Maustaste anklickt. Diese Menüs sind in der Regel
kontextabhängig und enthalten nur Befehle, die sich auf das Formular oder das Steuerelement mit dem
Eingabefokus beziehen. Man bezeichnet derartige Menüs deshalb auch als Kontextmenüs. Einer WPFAnwendung können Sie Kontextmenüs ganz einfach mit der Klasse ContextMenu hinzufügen.
<Window.Resources>
<ContextMenu x:Key="textBoxMenu">
<MenuItem Header="Name löschen" Name="cMenuClear"
Click="cMenuClear_Click"/>
</ContextMenu>
</Window.Resources>
<TextBox Margin="85,53,8,0" Name="txtBoxFirstName" Height="23"
ContextMenu="{StaticResource textBoxMenu}" VerticalAlignment="Top"
IsEnabled="False"></TextBox>
private void cMenuClear_Click(object sender, RoutedEventArgs e)
{
txtBoxFirstName.Text = String.Empty;
}
Windows-Standarddialogfelder
Es gibt eine Reihe von Standardaufgaben, bei denen der Benutzer bestimmte Arten von Informationen
bereitstellen muss. Die Microsoft .NET Framework-Klassenbibliothek stellt die Klassen
OpenFileDialog und SaveFileDialog bereit, die als Wrapper (Hüllklassen) für diese allgemeinen
Dialogfelder fungieren.
Die Klasse SaveFileDialog verwenden
SaveFileDialog saveFileDialog = new SaveFileDialog();
saveFileDialog.DefaultExt = ".txt";
saveFileDialog.AddExtension = true;
saveFileDialog.FileName = "Members";
saveFileDialog.InitialDirectory = @"C:\Temp";
saveFileDialog.OverwritePrompt = true;
saveFileDialog.Title = "Mitglieder";
saveFileDialog.ValidateNames = true;
if (saveFileDialog.ShowDialog().Value)
{
using (StreamWriter writer = new StreamWriter(saveFileDialog.FileName))
{
writer.WriteLine("Vorname: {0}", txtBoxFirstName.Text);
writer.WriteLine("Nachname: {0}", txtBoxLastName.Text);
MessageBox.Show("Mitgliedsdaten gespeichert", "Gespeichert");
}
}
Mirco De Roni
- 71 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
22 Eine Datenbank verwenden
Für dieses Kapitel müssen Sie Microsoft SQL Server installiert haben. Es empfiehlt sich, dass Sie ein
Konto mit Administratorberechtigungen verwenden.
Eine Datenbank mit ADO.NET abfragen
Die ADO.NET-Klassenbibliothek enthält ein umfangreiches Framework, mit dem sich Anwendungen
erstellen lassen, die Daten einer relationalen Datenbank abrufen und aktualisieren müssen. Jedes
Datenbankmanagementsystem (beispielsweise SQL Server, Oracle usw.) verfügt über einen eigenen
Datenanbieter, der eine Abstraktion der Mechanismen für die Verbindung zu einer Datenbank, das
Ausführen von Abfragen und das Aktualisieren von Daten implementiert.
Die Northwind-Datenbank
Northwind Traders (kurz Northwind) ist eine fiktive Firma, die Feinkost mit exotischen Namen verkauft.
Die Datenbank Northwind enthält mehrere Tabellen mit Informationen über die von der Firma verkauften
Artikel, die Kunden der Firma, die von den Kunden ausgelösten Bestellungen, die Lieferanten, von denen
Northwind Traders Waren zum Wiederverkauf bezieht, Speditionen für die Auslieferung der Waren an die
Kunden sowie Mitarbeiter, die für Northwind Traders tätig sind.
Als Vorbereitung müssen Sie zunächst die Northwind-Datenbank erstellen.
Bestellinformationen mit ADO.NET abfragen
Folgende using-Anweisung fügen Sie zuerst am Anfang der Datei hinzu:
using System.Data.SqlClient;
Der Namespace System.Data.SqlClient enthält die Klassen des SQL Server-Datenanbieters für
ADO.NET. Diese Klassen sind spezialisierte Versionen der ADO.NET-Klassen, die für die Arbeit mit SQL
Server optimiert wurden.
Mirco De Roni
- 72 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
namespace ReportOrders
{
class Program
{
static void Main(string[] args)
{
SqlConnection connection = new SqlConnection();
try
{
connection.ConnectionString =
"Integrated Security=true;Initial Catalog=Northwind;" +
"Data Source=PCSRV\\SQLEXPRESS";
connection.Open();
Console.Write("Bitte eine KundenID eingeben (5 Zeichen): ");
string customerId = Console.ReadLine();
SqlCommand command = new SqlCommand();
command.Connection = connection;
command.CommandText =
"SELECT OrderID, OrderDate, ShippedDate, ShipName,
ShipAddress, ShipCity, ShipCountry " +
"FROM Orders " +
"WHERE CustomerID='" + customerId + "'";
Console.WriteLine(command.CommandText + "\n");
SqlDataReader dataReader = command.ExecuteReader();
while (dataReader.Read())
{
int orderId = dataReader.GetInt32(0);
if (dataReader.IsDBNull(2))
{
Console.WriteLine("Bestellung " + orderId + " noch nicht
versandt\n\n");
}
else
{
DateTime orderDate = dataReader.GetDateTime(1);
DateTime shippedDate = dataReader.GetDateTime(2);
string shipName = dataReader.GetString(3);
string shipAddress = dataReader.GetString(4);
string shipCity = dataReader.GetString(5);
string shipCountry = dataReader.GetString(6);
Console.WriteLine
(
"Bestellung: " + orderId + "\n" +
"Aufgegeben: " + orderDate + "\n" +
"Geliefert: " + shippedDate + "\n" +
"Lieferungsname: " + shipName + "\n" +
"Lieferadresse: " + shipAddress + "\n" +
"Stadt: " + shipCity + "\n" +
"Land: " + shipCountry + "\n"
);
}
}
dataReader.Close();
}
catch (SqlException ex)
{
Console.WriteLine("Fehler beim Zugriff auf die Datenbank:\n" +
ex.Message);
}
finally
Mirco De Roni
- 73 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
{
connection.Close();
}
Console.ReadLine();
}
}
}
Eine Datenbank mit DLINQ abfragen
LINQ bietet Abfrageausdrücke mit einer SQL-ähnlichen Syntax, um Abfragen auszuführen und eine
Ergebnismenge zu generieren, die sich schrittweise durchlaufen lässt. Mit der erweiterten Form von LINQ
namens DLINQ können Sie den Inhalt einer Datenbank abfragen und manipulieren. DLINQ setzt auf
ADO.NET auf und bietet eine höhere Ebene der Abstraktion.
Eine Entitätsklasse definieren
LINQ verlangt, dass die abgefragten Objekte aufzählbar sind. Es muss sich um Auflistungen handeln, die
die Schnittstelle IEnumerable implementieren. DLINQ kann seine eigenen aufzählbaren Auflistungen
von Objekten erstellen und zwar basierend auf Klassen, die Sie definieren und die sich direkt auf
Tabellen in einer Datenbank abbilden lassen. Diese Klassen bezeichnet man als Entitätsklassen.
Wenn Sie die Verbindung zu einer Datenbank herstellen und eine Abfrage ausführen, kann DLINQ die
von der Abfrage bezeichneten Daten abrufen und für jede abgerufene Zeile eine Instanz einer
Entitätsklasse erstellen.
CREATE TABLE "Products" (
"ProductID" "int" IDENTITY (1, 1) NOT NULL ,
"ProductName" nvarchar (40) NOT NULL ,
"SupplierID" "int" NULL ,
"UnitPrice" "money" NULL,
CONSTRAINT "PK_Products" PRIMARY KEY CLUSTERED ("ProductID"),
CONSTRAINT "FK_Products_Suppliers" FOREIGN KEY ("SupplierID")
REFERENCES "dbo"."Suppliers" ("SupplierID")
)
Eine Entitätsklasse, die der Tabelle Products entspricht, können Sie wie folgt definieren:
[Table(Name = "Products")]
public class Product
{
[Column(IsPrimaryKey = true, CanBeNull = false)]
public int ProductID { get; set; }
[Column(CanBeNull = false)]
public string ProductName { get; set; }
[Column]
public int? SupplierID { get; set; }
[Column(DbType = "money")]
public decimal? UnitPrice { get; set; }
}

Das Attribut Table kennzeichnet diese Klasse als Entitätsklasse. Der Parameter Name gibt den
Namen der korrespondierenden Tabelle in der Datenbank an. Wenn Sie den Parameter
weglassen, nimmt DLINQ an, dass der Name der Entitätsklasse gleich dem Namen der
entsprechenden Tabelle in der Datenbank ist.

Das Attribut Column beschreibt, wie eine Spalte in der Tabelle Products einer Eigenschaft in der
Klasse Product zugeordnet wird.
Mirco De Roni
- 74 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________

Der Parameter IsPrimaryKey gibt an, dass die Eigenschaft einen Teil des Primärschlüssels
bildet.

Der Parameter CanBeNull gibt an, ob die Spalte in der Datenbank einen NULL-Wert enthalten
kann. Der Standardwert für den Parameter CanBeNull ist true.

Der Parameter DbType gibt den Typ der zugrunde liegenden Spalte in der Datenbank an. In
vielen Fällen kann DLINQ Daten in einer Spalte der Datenbank erkennen und in den Typ der
entsprechenden Eigenschaft in der Entitätsklasse konvertieren.
Bestellinformationen mit einer DLINQ-Abfrage abrufen
Als erstes klicken Sie im Menü Projekt auf Verweis hinzufügen. Gehen Sie im Dialogfeld Verweis
hinzufügen auf die Registerkarte .NET, markieren Sie die Assembly System.Data.Linq und klicken Sie
dann auf OK. Diese Assembly enthält die DLINQ-Typen und -Attribute.
using
using
using
using
using
using
using
System;
System.Collections.Generic;
System.Linq;
System.Text;
System.Data.Linq;
System.Data.Linq.Mapping;
System.Data.SqlClient;
namespace DLINQOrders
{
class Program
{
static void Main(string[] args)
{
Northwind northwindDB = new Northwind(
"Integrated Security=true;Initial Catalog=Northwind;" +
"Data Source=PCSRV\\SQLEXPRESS");
try
{
Console.Write("Bitte eine KundenID eingeben (5 Zeichen): ");
string customerId = Console.ReadLine();
var ordersQuery = from o in northwindDB.Orders
where String.Equals(o.CustomerID, customerId)
select o;
foreach (var order in ordersQuery)
{
if (order.ShippedDate == null)
{
Console.WriteLine("Bestellung " + order.OrderID + " noch
nicht versandt\n\n");
}
else
{
Console.WriteLine
(
"Bestellung: " + order.OrderID + "\n" +
"Aufgegeben: " + order.OrderDate + "\n" +
"Geliefert: " + order.ShippedDate + "\n" +
"Lieferungsname: " + order.ShipName + "\n" +
"Lieferadresse: " + order.ShipAddress + "\n" +
"Stadt: " + order.ShipCity + "\n" +
"Land: " + order.ShipCountry + "\n"
);
}
}
}
Mirco De Roni
- 75 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
catch (SqlException ex)
{
Console.WriteLine("Fehler beim Zugriff auf die Datenbank:\n" +
ex.Message);
}
Console.ReadLine();
}
}
[Table(Name = "Orders")]
public class Order
{
[Column(IsPrimaryKey = true, CanBeNull = false)]
public int OrderID { get; set; }
[Column]
public string CustomerID { get; set; }
[Column]
public DateTime? OrderDate { get; set; }
[Column]
public DateTime? ShippedDate { get; set; }
[Column]
public string ShipName { get; set; }
[Column]
public string ShipAddress { get; set; }
[Column]
public string ShipCity { get; set; }
[Column]
public string ShipCountry { get; set; }
}
public class Northwind : DataContext
{
public Table<Order> Orders;
public Northwind(string connectionInfo) : base(connectionInfo)
{
}
}
}
Mirco De Roni
- 76 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
23 Einen Webdienst erstellen und verwenden
Was ist ein Webdienst?
Ein Webdienst – oder Web Service – ist eine Geschäftskomponente, die den Clients (Consumer) eine
bestimmte Funktionalität bereitstellt.
Die Rolle von SOAP
Das Simple Object Access Protocol (SOAP) ist das Protokoll, nach dem die Clientanwendungen
Anforderungen an Webdienste senden und Antworten von Webdiensten empfangen. SOAP ist ein
einfaches und kompaktes Protokoll, das auf HTTP – dem im Web zum Senden und Empfangen von
HTML-Seiten verwendeten Protokoll – aufsetzt.
Es definiert eine XML-Grammatik für



die Benennung von Methoden, die ein Client auf einem Webdienst aufrufen möchte,
die Definition von Parametern und Rückgabewerten sowie
die Beschreibung der Typen von Parametern und Rückgabewerten.
Wenn ein Client einen Webdienst aufruft, muss er die Methode und ihre Parameter mithilfe dieser XMLGrammatik spezifizieren.
SOAP ist ein Industriestandard mit der Aufgabe, die plattformübergreifende Interoperabilität zu
verbessern. Die Stärke von SOAP liegt in seiner Einfachheit und gründet sich auch darauf, dass es auf
anderen Industriestandard-Techniken basiert: HTTP und XML.
Die SOAP-Spezifikation definiert vor allem




das Format einer SOAP-Meldung,
wie Daten zu kodieren sind,
wie Meldungen (Methodenaufrufe) zu senden sind und
wie Antworten verarbeitet werden.
Was ist die Web Services Description Language?
Der Körper einer SOAP-Meldung ist ein XML-Dokument. Wenn eine Clientanwendung eine Webmethode
aufruft, erwartet der Webserver, dass der Client die Parameter für die Methode mit einem bestimmten
Satz von Tags kodiert. Woher weiss nun ein Client, welche Tags oder welches XML-Schema er
verwenden soll? Er erfährt es dadurch, dass der Webdienst nach Aufforderung eine Beschreibung von
sich selbst liefert. Die Antwort des Webdienstes ist ein anderes XML-Dokument, das den Webdienst
beschreibt. Das für dieses Dokument verwendete XML-Schema ist standardisiert worden und heisst Web
Services Description Language (WSDL). Diese Beschreibung bietet genügend Informationen, damit eine
Clientanwendung eine SOAP-Anforderung in einem Format konstruieren kann, die der Webserver
verstehen sollte.
Einen Webdienst erstellen
Um einen Webdienst zu erstellen, klicken Sie in Visual Studio auf das Menü Datei  Neu  Projekt….
Anschliessend wählen Sie den Eintrag ASP.NET-Webdienstanwendung.
Mirco De Roni
- 77 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
using
using
using
using
using
System;
System.Collections.Generic;
System.Linq;
System.Web;
System.Web.Services;
namespace Webservice
{
/// <summary>
/// Zusammenfassungsbeschreibung für Service1
/// </summary>
[WebService(Namespace = "http://microsoft.com/webservices/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
// Um das Aufrufen dieses Webdiensts aus einem Skript mit ASP.NET AJAX
zuzulassen, heben Sie die Auskommentierung der folgenden Zeile auf.
// [System.Web.Script.Services.ScriptService]
public class Service1 : System.Web.Services.WebService
{
[WebMethod]
public string getMessage()
{
return "Mirco De Roni";
}
}
}
Mirco De Roni
- 78 -
Zusammenfassung
Microsoft Visual C# 2008 - Schritt für Schritt
_____________________________________________________________________________________________
24 Quellenverzeichnis
Literatur
Sharp, John, Microsoft Visual C# 2008 – Schritt für Schritt, 2008
Mirco De Roni
- 79 -
Zusammenfassung
Herunterladen