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

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

Download:
- Beispiele, ca. 62,4 MB

Jetzt Buch bestellen
Ihre Meinung?

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

Visual C# 2012
Rheinwerk Computing
1402 S., 6., aktualisierte und erweiterte Auflage 2013, geb., mit DVD
49,90 Euro, ISBN 978-3-8362-1997-6
Pfeil 10 Weitere C#-Sprachfeatures
Pfeil 10.1 Implizit typisierte Variablen
Pfeil 10.2 Anonyme Typen
Pfeil 10.3 Lambda-Ausdrücke
Pfeil 10.3.1 Projektion und Prädikat
Pfeil 10.4 Erweiterungsmethoden
Pfeil 10.5 Partielle Methoden
Pfeil 10.5.1 Wo partielle Methoden eingesetzt werden
Pfeil 10.6 Operatorüberladung
Pfeil 10.6.1 Einführung
Pfeil 10.6.2 Die Syntax der Operatorüberladung
Pfeil 10.6.3 Die Operatorüberladungen im Projekt »GeometricObjectsSolution«
Pfeil 10.6.4 Die Operatoren »true« und »false« überladen
Pfeil 10.6.5 Benutzerdefinierte Konvertierungen
Pfeil 10.7 Indexer
Pfeil 10.7.1 Überladen von Indexern
Pfeil 10.7.2 Parameterbehaftete Eigenschaften
Pfeil 10.8 Attribute
Pfeil 10.8.1 Das »Flags«-Attribut
Pfeil 10.8.2 Benutzerdefinierte Attribute
Pfeil 10.8.3 Attribute auswerten
Pfeil 10.8.4 Festlegen der Assembly-Eigenschaften in »Assembly-Info.cs«
Pfeil 10.9 Dynamisches Binden
Pfeil 10.9.1 Eine kurze Analyse
Pfeil 10.9.2 Dynamische Objekte
Pfeil 10.10 Unsicherer (unsafe) Programmcode – Zeigertechnik in C#
Pfeil 10.10.1 Einführung
Pfeil 10.10.2 Das Schlüsselwort »unsafe«
Pfeil 10.10.3 Die Deklaration von Zeigern
Pfeil 10.10.4 Die »fixed«-Anweisung
Pfeil 10.10.5 Zeigerarithmetik
Pfeil 10.10.6 Der Operator »->«

Rheinwerk Computing - Zum Seitenanfang

10.10 Unsicherer (unsafe) Programmcode – Zeigertechnik in C#Zur nächsten Überschrift


Rheinwerk Computing - Zum Seitenanfang

10.10.1 EinführungZur nächsten ÜberschriftZur vorigen Überschrift

Manchmal ist es erforderlich, auf die Funktionen einer in C geschriebenen herkömmlichen DLL zuzugreifen. Viele C-Funktionen erwarten jedoch Zeiger auf bestimmte Speicheradressen oder geben solche als Aufrufergebnis zurück. Es kann auch vorkommen, dass in einer Anwendung der Zugriff auf Daten erforderlich ist, die sich nicht im Hauptspeicher, sondern beispielsweise im Grafikspeicher befinden. Das Problem ist im ersten Moment, dass C#-Code, der unter der Obhut der CLR läuft und als sicherer bzw. verwalteter (managed) Code eingestuft wird, keine Zeiger auf Speicheradressen gestattet.

Ein Entwickler, der mit dieser Einschränkung in seiner Anwendung nicht leben kann, muss unsicheren Code schreiben. Trotz dieser seltsamen Bezeichnung ist unsicherer Code selbstverständlich nicht wirklich »unsicher« oder wenig vertrauenswürdig. Es handelt sich hierbei lediglich um C#-Code, der die Typüberprüfung durch den Compiler einschränkt und den Einsatz von Zeigern und Zeigeroperationen ermöglicht.


Rheinwerk Computing - Zum Seitenanfang

10.10.2 Das Schlüsselwort »unsafe«Zur nächsten ÜberschriftZur vorigen Überschrift

Der Kontext, in dem unsicherer Code gewünscht wird, muss mit Hilfe des Schlüsselworts unsafe deklariert werden. Es kann eine komplette Klasse oder eine Struktur ebenso als unsicher markiert werden wie eine einzelne Methode. Es ist sogar möglich, innerhalb des Anweisungsblocks einer Methode einen Teilbereich als unsicher zu kennzeichnen.

Ganz allgemein besteht ein nicht sicherer Bereich aus Code, der in geschweiften Klammern eingeschlossen ist und dem das Schlüsselwort unsafe vorangestellt wird. Im folgenden Codefragment wird die Methode Main als unsicher deklariert:

static unsafe void Main(string[] args) {
[...]
}

Listing 10.53 Definition einer »unsafe«-Methode

Die Angabe von unsafe ist aber allein noch nicht ausreichend, um unsicheren Code kompilieren zu können. Zusätzlich muss auch noch der Compilerschalter /unsafe gesetzt werden. In Visual Studio 2012 legen Sie diesen Schalter im Projekteigenschaftsfenster unter Erstellen Unsicheren Code zulassen fest. Wenn Sie vergessen, den Compilerschalter einzustellen, wird bei der Kompilierung ein Fehler generiert.


Rheinwerk Computing - Zum Seitenanfang

10.10.3 Die Deklaration von ZeigernZur nächsten ÜberschriftZur vorigen Überschrift

In C/C++ sind Zeiger ein klassisches Hilfsmittel der Programmierung, in .NET hingegen nehmen Zeiger eine untergeordnete Rolle ein und werden meist nur in Ausnahmesituationen benutzt. Wir werden daher nicht allzu tief in die Thematik einsteigen und uns auf das Wesentlichste konzentrieren. Wenn Sie keine Erfahrungen mit der Zeigertechnik in C oder in anderen zeigerbehafteten Sprachen gesammelt haben und sich dennoch weiter informieren wollen, sollten Sie C-Literatur zur Hand nehmen.

Zeiger sind Verweise auf Speicherbereiche und werden allgemein wie folgt deklariert:

Datentyp* Variable

Dazu ein Beispiel. Mit der Deklaration

int value = 4711;
int* pointer;

erzeugen wir eine int-Variable namens value und eine Zeigervariable pointer. pointer ist noch kein Wert zugewiesen und zeigt auf eine Speicheradresse, deren Inhalt als Integer interpretiert wird. Der *-Operator ermöglicht die Deklaration eines typisierten Zeigers und bezieht sich auf den vorangestellten Typ – hier Integer.

Wollen wir dem Zeiger pointer mitteilen, dass er auf die Adresse der Variablen value zeigen soll, müssen wir pointer die Adresse von value übergeben:

pointer = &value;

Der &-Adressoperator liefert eine physikalische Speicheradresse. In der Anweisung wird die Adresse der Variablen value ermittelt und dem Zeiger pointer zugewiesen.

Wollen wir den Inhalt der Speicheradresse erfahren, auf die der Zeiger verweist, muss dieser dereferenziert werden:

Console.WriteLine(*pointer);

Das Ergebnis wird 4711 lauten.

Fassen wir den gesamten (unsicheren) Code zusammen. Wenn Sie die Zeigertechnik unter C kennen, werden Sie feststellen, dass es syntaktisch keinen Unterschied gibt:

class Program {
static unsafe void Main(string[] args) {
int value = 4711;
int* pointer;
pointer = &value;
Console.WriteLine(*pointer);
}
}

Listing 10.54 Zeigertechnik mit C#

C# gibt einen Zeiger nur von einem Wertetyp und niemals von einem Referenztyp zurück. Das gilt jedoch nicht für Arrays und Zeichenfolgen, da Variablen dieses Typs einen Zeiger auf das erste Element bzw. den ersten Buchstaben liefern.


Rheinwerk Computing - Zum Seitenanfang

10.10.4 Die »fixed«-AnweisungZur nächsten ÜberschriftZur vorigen Überschrift

Während der Ausführung eines Programms werden dem Heap viele Objekte hinzugefügt oder aufgegeben. Um eine unnötige Speicherbelegung oder Speicherfragmentierung zu vermeiden, schiebt der Garbage Collector die Objekte hin und her. Auf ein Objekt zu zeigen ist natürlich wertlos, wenn sich seine Adresse unvorhersehbar ändern könnte. Die Lösung dieser Problematik bietet die fixed-Anweisung. fixed weist den Garbage Collector an, das Objekt zu »fixieren« – es wird danach nicht mehr verlagert. Da sich dies negativ auf das Verhalten der Laufzeitumgebung auswirken kann, sollten als fixed deklarierte Blöcke nur kurzzeitig benutzt werden.

Hinter der fixed-Anweisung wird in runden Klammern ein Zeiger auf eine verwaltete Variable festgelegt. Diese Variable ist diejenige, die während der Ausführung fixiert wird.

fixed (<Typ>* <pointer> = <Ausdruck>)
{
[...]
}

Ausdruck muss dabei implizit in Typ* konvertierbar sein.

Am besten sind die Wirkungsweise und der Einsatz von fixed anhand eines Beispiels zu verstehen. Sehen Sie sich daher zuerst das folgende Listing an:

class Program {
int value;
static void Main() {
Program obj = new Program();
// unsicherer Code
unsafe {
// fixierter Code
fixed(int* pointer = &obj.value) {
*pointer = 9;
System.Console.WriteLine(*pointer);
}
}
}
}

Listing 10.55 Fixierter Programmcode

Im Code wird ein Objekt vom Typ Program in Main erzeugt. Es kann grundsätzlich nicht garantiert werden, dass das Program-Objekt obj vom Garbage Collector nicht im Speicher verschoben wird. Da der Zeiger pointer auf das objekteigene Feld value verweist, muss sichergestellt sein, dass sich das Objekt bei der Auswertung des Zeigers immer noch an derselben physikalischen Adresse befindet. Die fixed-Anweisung mit der Angabe, worauf pointer zeigt, garantiert, dass die Dereferenzierung an der Konsole das richtige Ergebnis ausgibt.

Beachten Sie, dass in diesem Beispiel nicht die gesamte Methode als unsicher markiert ist, sondern nur der Kontext, in dem der Zeiger eine Rolle spielt.


Rheinwerk Computing - Zum Seitenanfang

10.10.5 ZeigerarithmetikZur nächsten ÜberschriftZur vorigen Überschrift

Sie können in C# Zeiger addieren und subtrahieren, so wie in C oder in anderen Sprachen. Dazu bedient sich der C#-Compiler intern des sizeof-Operators, der die Anzahl der Bytes zurückgibt, die von einer Variablen des angegebenen Typs belegt werden. Addieren Sie beispielsweise zu einem Zeiger vom Typ int* den Wert 1, verweist der Zeiger auf eine Adresse, die um 4 Byte höher liegt, da ein Integer eine Breite von 4 Byte hat.

Im folgenden Beispiel wird ein int-Array initialisiert. Anschließend werden die Inhalte der Array-Elemente nicht wie üblich über ihren Index, sondern mittels Zeigerarithmetik an der Konsole ausgegeben.

class Program {
unsafe static void Main(string[] args) {
int[] arr = {10, 72, 333, 4550};
fixed(int* pointer = arr) {
Console.WriteLine(*pointer);
Console.WriteLine(*(pointer + 1));
Console.WriteLine(*(pointer + 2));
Console.WriteLine(*(pointer + 3));
}
}
}

Listing 10.56 Zeigerarithmetik mit C#

Ein Array ist den Referenztypen und damit den verwalteten Typen zuzurechnen. Der C#-Compiler erlaubt es aber nicht, außerhalb einer fixed-Anweisung mit einem Zeiger auf einen verwalteten Typ zu zeigen. Mit

fixed(int* pointer = arr)

kommen wir dieser Forderung nach. Das Array arr wird implizit in den Typ int* konvertiert und ist gleichwertig mit folgender Anweisung:

int* pointer = &arr[0]

In der ersten Ausgabeanweisung wird pointer dereferenziert und der Inhalt 10 angezeigt, weil ein Zeiger auf ein Array immer auf das erste Element zeigt. In den folgenden Ausgaben wird die Ausgabeadresse des Zeigers um jeweils eine Integer-Kapazität erhöht, also um jeweils 4 Byte. Da die Elemente eines Arrays direkt hintereinander im Speicher abgelegt sind, werden der Reihe nach die Zahlen 72, 333 und 4550 an der Konsole angezeigt.


Rheinwerk Computing - Zum Seitenanfang

10.10.6 Der Operator »->«Zur vorigen Überschrift

Strukturen sind Wertetypen aus mehreren verschiedenen Elementen auf dem Stack und können ebenfalls über Zeiger angesprochen werden. Nehmen wir an, die Struktur Point sei wie folgt definiert:

public struct Point {
public int X;
public int Y;
}

Innerhalb eines unsicheren Kontexts können wir uns mit

Point point = new Point();
Point* ptr = &point;

einen Zeiger auf ein Objekt vom Typ Point besorgen. Beabsichtigen wir, das Feld X zu manipulieren und ihm den Wert 150 zuzuweisen, muss der Zeiger ptr zuerst dereferenziert werden. Mittels Punktnotation wird dann das Feld angegeben, dem der Wert zugewiesen werden soll. Der gesamte Ausdruck sieht dann wie folgt aus:

(*ptr).X = 150;

C# bietet uns mit dem Operator »->« eine einfache Kombination aus Dereferenzierung und Feldzugriff an. Der Ausdruck kann daher gleichwertig auch so formuliert werden:

ptr->X = 150;


Ihre Meinung

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

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

Visual C# 2012
Jetzt Buch bestellen


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

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






 Professionell
 entwickeln mit
 Visual C# 2012


Zum Rheinwerk-Shop: Windows Presentation Foundation






 Windows Presentation
 Foundation


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






 Schrödinger
 programmiert C++


Zum Rheinwerk-Shop: C++ Handbuch






 C++ Handbuch


Zum Rheinwerk-Shop: C/C++






 C/C++


 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und der Schweiz
InfoInfo





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


Nutzungsbestimmungen | Datenschutz | Impressum

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

Cookie-Einstellungen ändern