4 Visual Basic .NET-Datentypen und -Features

Werbung
4
115
116
119
129
130
Visual Basic .NET-Datentypen
und -Features
Grundlegendes zu Datentypen
Visual Basic .NET-Datentypen
Datentypenfeatures
Garbage Collection: Weg mit den Objekten
Fazit
Bisher haben wir anhand einiger einfacher Beispiele die Programmerstellung in Visual Basic .NET
untersucht. Wie Sie erfahren haben, ist ein Verständnis der objektorientierten Programmierung in
Visual Basic .NET für beinahe jede Aufgabe unerlässlich – selbst für das Anzeigen und Verwenden
eines einfachen Formulars.
Ein weiteres Konzept, das Sie verinnerlichen müssen, sind die in Visual Basic .NET verwendeten
Datentypen. Ein Datentyp ist der Entwurf für den Aufbau eines Speicherbereichs. Dieser Entwurf legt
den Bereich der speicherbaren Werte sowie die Operationen fest, die im Speicher ausgeführt werden
können. Sämtliche Variablen, Arrays, Konstanten, Eigenschaften, Prozedurargumente und Prozedurrückgabewerte verfügen über einen Datentyp. Sie werden bald merken, dass das Konzept der Datentypen mehr als nur numerische Typen umfasst – es gilt für alle Objekte.
Grundlegendes zu Datentypen
Wie Sie wissen, ist eine Variable eigentlich der Name eines Speicherortes zur Speicherung von Daten.
Bei der Dimensionierung einer Variable erhält diese einen Namen und einen Datentyp. Der Datentyp
der Variable legt fest, wie die Daten im Computerspeicher abgelegt werden.
Viele klassische Visual Basic-Programmierer hatten nur wenig mit Datentypen zu tun. Mal verwendeten sie nicht dimensionierte Variablen, dann wieder Variant-Variablen zur Speicherung von Zeichenfolgen, Ganzzahlen oder Booleschen Werten. In den früheren Visual Basic-Versionen wurde dem
Programmierer im Hinblick auf die Datentypen relativ freie Hand gelassen. Wenn Sie eine Variable
nicht dimensionierten, wies Visual Basic dieser den Standarddatentyp zu – einen 16-Byte-Variant-Typ.
Obwohl der Variant-Typ für einige Operationen offiziell eingesetzt werden kann, z.B. zur Speicherung
eines Verweises auf ein Excel-Tabellenobjekt, ist doch der Variant-Typ auch immer der letzte Ausweg
für so manchen schludrigen Programmierer. Ich habe schon Visual Basic-Code gesehen, in dem jede
einzelne Variable vom Typ Variant war. Diese Ungenauigkeit führt nicht nur zu einer Speicherverschwendung, sondern ist auch gefährlich. Sie konnten einer Variant-Variable beispielsweise einen
Double-Wert zuordnen und der Variable dann versehentlich eine Zeichenfolge zuweisen. Der Compiler
im klassischen Visual Basic blinzelt bei dieser eklatanten Fehlzuordnung nicht einmal.
115
Microsoft Corporation: Microsoft SQL Server 2000 Systemverwaltung - Original Microsoft Training: Examen 70-228. ISBN: 3-86063-919-6. Microsoft Press 2001
In Visual Basic .NET gelten bezüglich der Variablenverwendung sehr viel strengere Richtlinien. Der
einer Variablen zugewiesene Wert muss mit dem Variablentyp zuweisungskompatibel sein. Wenn Sie
eine Variable mit dem Typ Integer deklarieren, können Sie dieser nicht automatisch einen Short-Wert
zuweisen. Visual Basic .NET unterstützt ferner keine Typerzwingung. Diejenigen unter Ihnen, die
gerne Codezeilen wie z.B. myString = "The number is " + 10 schreiben, werden sich also vorsehen
müssen.
Visual Basic .NET-Datentypen
Visual Basic .NET verwendet zwei Variablentypen: Werttypen und Verweistypen. Es ist aus verschiedenen Gründen wichtig, den Unterschied zwischen den Wert- und den Verweistypen zu kennen:
b Wert- und Verweistypen werden vom Speicherverwaltungssystem unterschiedlich gehandhabt.
b Wert- und Verweistypen werden in Gleichheitsprüfungen unterschiedlich behandelt.
b Wert- und Verweistypen werden von der CLR (Common Language Runtime) unterschiedlich initialisiert.
b Wert- und Verweistypen werden in Zuweisungsanweisungen unterschiedlich behandelt.
Eine Variable ist vom Werttyp, wenn sie Daten in einem eigenen Speicherbereich speichert. Ein Verweistyp dagegen enthält einen Verweis (oder Zeiger) auf einen Speicherbereich, in dem sich die Daten
befinden. Zu den Werttypen zählen alle numerischen und binären Datentypen, z.B. der Integer-, der
Char- und der Date-Typ. Zu den Verweistypen gehören Zeichenfolgen, Arrays und sämtliche Klassen.
Sehen Sie sich das folgende Codefragment an:
Dim
Dim
Dim
Dim
newEmp1 As New myClass()
newEmp2 As New myClass()
iInteger1 As Integer = 12
iInteger2 As Integer = 12
MessageBox.Show(iInteger1.Equals(iInteger2).ToString) ‘True
MessageBox.Show(newEmp1.Equals(newEmp2).ToString)
newEmp2 = newEmp1
MessageBox.Show(newEmp1.Equals(newEmp2).ToString)
‘False
‘True
Dieses Beispiel enthält zwei Wertvariablen (iInteger1 und iInteger2) und zwei Verweisvariablen
(newEmp1 und newEmp2). Sowohl iInteger1 als auch iInteger2 wird der Wert 12 zugewiesen. Aufgrund der identischen Daten sind diese Variablen scheinbar gleichwertig, im Meldungsfeld erscheint
der Wert True. Diese zwei Variablen sind jedoch nicht identisch, da sie unabhängig voneinander vorliegen und zwei unterschiedliche Speicherbereiche belegen. Wenn wir der Variablen iInteger1 den
Wert 42 zuweisen, bleibt der Wert von iInteger2 dennoch 12.
Sehen wir uns nun den Abschnitt zu den Verweisvariablen newEmp1 und newEmp2 an. Diese Variablen verweisen anfänglich auf zwei unterschiedliche Instanzen von myClass, daher wird im ersten
Meldungsfeld der Wert False ausgegeben. Als Nächstes wird newEmp1 der Variablen newEmp2 zugewiesen. Da es sich bei beiden Variablen um Verweisvariablen handelt, referenzieren sie nun dasselbe
Objekt im selben Speicherbereich, wie dargestellt in Abbildung 4.11. Sobald eines der Datenfelder in
newEmp1 geändert wird, ändert sich auch newEmp2, da beide Variablen auf denselben Speicherort
verweisen.
116
Microsoft Corporation: Microsoft SQL Server 2000 Systemverwaltung - Original Microsoft Training: Examen 70-228. ISBN: 3-86063-919-6. Microsoft Press 2001
Kapitel 4
iInteger1
12
iInteger2
12
newEmp1
myClass
newEmp2
Abbildung 4.1: Verweisvariablen zeigen auf Speicherbereiche
Wenn zwei Verweisvariablen auf Gleichheit geprüft werden, wird im Grunde geprüft, ob beide Variablen auf denselben Speicherbereich verweisen. Ist dies (wie in Abbildung 4.1) der Fall, werden sie als
gleich betrachtet. Wenn die Variablen jedoch auf unterschiedliche Objekte desselben Typs verweisen –
selbst wenn beide Objekte Byte für Byte die gleichen Werte aufweisen – werden die Variablen als
ungleich eingestuft.
Werttypen
Ein Werttyp wird im .NET Framework auch als primitiver Typ bezeichnet. (Ein primitiver Typ ist ein
Datentyp, der per Voreinstellung vom Compiler unterstützt wird. Alle primitiven Typen sind Werttypen.) Auf Werttypen wird immer direkt zugegriffen. Es ist nicht möglich, einen Werttyp zu referenzieren. Im Gegensatz zu Verweistypen können Werttypen nicht auf Null gesetzt werden. Werttypen
enthalten immer einen Wert, selbst wenn dieser noch nicht zugewiesen wurde. Bei der Dimensionierung einer Werttypvariable wird diese mit einem stellvertretenden Wert für den jeweiligen Typ initialisiert. Wenn Sie beispielsweise eine Integer-Variable dimensionieren und dieser keinen Wert zuweisen,
initialisiert der Visual Basic .NET-Compiler die Variable automatisch mit dem Wert 0.
Die primitiven Typen von Visual Basic werden über Schlüsselwörter identifiziert, die eigentlich Aliasse
für vordefinierte Strukturtypen im System-Namespace darstellen. Dies bedeutet, dass ein primitiver
Typ und der als Alias verwendete Strukturtyp absolut nicht zu unterscheiden sind. Das Visual BasicSchlüsselwort Byte ist genau dasselbe wie System.Byte.
Werttypen werden versiegelt, d.h. von einem Werttyp können keine weiteren Typen abgeleitet werden.
Jedem Werttyp ist ein spezifischer Speicherblock fester Länge zugewiesen und jeder Werttyp wird –
wie bereits gesagt – durch den Compiler automatisch mit einem bestimmten Wert initialisiert. In
Tabelle 4.1 werden die Visual Basic .NET-Werttypen aufgelistet.
Visual Basic-Typ
.NET-Laufzeittypstruktur
Speicherbereichsgröße
Standardwert
Wertebereich
Boolean
System.Boolean
4 Bytes
False
True oder False
Byte
System.Byte
1 Byte
0
0 bis 255 (ohne Vorzeichen)
Char
System.Char
2 Bytes
Chr(0)
0 bis 65.535 (ohne Vorzeichen)
Date
System.DateTime
8 Bytes
# 01/01/0001
12:00:00AM #
1. Januar 1 bis 31. Dezember 9999
Visual Basic .NET-Datentypen und -Features
Microsoft Corporation: Microsoft SQL Server 2000 Systemverwaltung - Original Microsoft Training: Examen 70-228. ISBN: 3-86063-919-6. Microsoft Press 2001
117
Visual Basic-Typ
.NET-Laufzeittypstruktur
Speicherbereichsgröße
Standardwert
Wertebereich
Decimal
System.Decimal
12 Bytes
0D
+/− 79.228.162.514.264.337.593.543.
950.335 ohne Dezimalkomma;
+/− 7,9228162514264337593543950
335 mit 28 Stellen rechts vom Dezimalkomma; kleinste Zahl ungleich Null lautet
+/− 0.0000000000000000000000000001
Double
(Gleitkommatyp
mit doppelter
Genauigkeit)
System.Double
8 Bytes
0.0
− 1,79769313486231E308 bis
− 4,94065645841247E-324 für negative
Werte; 4,94065645841247E-324 bis
1,79769313486232E308 für positive Werte
Integer
System.Int32
4 Bytes
0
− 2.147.483.648 bis 2.147.483.647
Long
(lange Ganzzahl)
System.Int64
8 Bytes
0
- 9.223.372.036.854.775.808 bis
9.223.372.036.854.775.807
Short
System.Int16
2 Bytes
0
− 32.768 bis 32.767
Single
(Gleitkommatyp
mit einfacher
Genauigkeit)
System.Single
4 Bytes
0.0
− 3,402823E38 bis
− 1,401298E-45 für negative Werte;
1,401298E-45 bis
3,402823E38 für positive Werte
Structure
System.ValueType
Auch wenn einige Member vom Verweistyp sein können, ist eine Struktur ein Werttyp.
Tabelle 4.1: Visual Basic .NET-Werttypen
ANMERKUNG: Der Datentyp Currency aus dem klassischen Visual Basic fällt im .NET Framework
weg. Bei Währungsoperationen müssen Sie den Datentyp Decimal mit zwei Dezimalstellen verwenden, um Rundungsfehler zu vermeiden.
Der Structure-Datentyp ist ein Legacytyp; es handelt sich hierbei um den Visual Basic .NET-Namen für
den benutzerdefinierten Typ in früheren Visual Basic-Versionen. Ein Structure-Typ ist eine Verkettung
von einem oder mehreren Membern eines Datentyps, wie nachfolgend gezeigt:
Structure DriveInfo
DriveNumber() As Short
DriveType As String
DriveSpace as Long
AvailableSpace as Long
End Structure
Eine Struktur wird als eine Einheit betrachtet, auch wenn einzeln auf die Member zugegriffen werden
kann. Für Strukturen gelten zwei Einschränkungen: Sie können nicht explizit von einem anderen Typ
erben (auch wenn sie implizit die Methoden der System.Object-Klasse erben), und eine Klasse kann
nicht von einer Struktur erben.
Strukturen werden in der objektorientierten Programmierung eher mit Stirnrunzeln betrachtet. Eine
Klasse besitzt sämtliche Fähigkeiten einer Struktur – sogar mehr –, daher sollten Sie anstelle von
Strukturen Klassen verwenden.
Verweistypen
Wie bereits angesprochen, verweist eine Verweisvariable auf den Speicherbereich, in dem die Variablendaten gespeichert werden. Auf diese Weise kann der Garbage Collector ein zum Löschen markiertes Objekt verfolgen und den Objektspeicher freigeben, wenn dieser nicht länger benötigt wird.
118
Microsoft Corporation: Microsoft SQL Server 2000 Systemverwaltung - Original Microsoft Training: Examen 70-228. ISBN: 3-86063-919-6. Microsoft Press 2001
Kapitel 4
Eine Verweisvariable enthält immer einen Verweis auf ein Objekt des entsprechenden Typs oder nichts
(Nothing), wenn Sie die Variable nicht explizit initialisiert haben. (Ein Nullzeiger verweist auf nichts.
Er kann ausschließlich dazu verwendet werden, der Variablen einen zulässigen Wert zuzuweisen.) In
Tabelle 4.2 werden die Visual Basic .NET-Verweistypen aufgelistet.
Visual Basic-Typ
.NET-Laufzeittypstruktur
Speicherbereichsgröße
Wertebereich
Object
System.Object (Klasse)
4 Bytes
verschieden
String
(variable Länge)
System.String (Klasse)
10 + (2 × stringLänge) Bytes
0 bis ca. 2 Milliarden Unicode-Zeichen
Tabelle 4.2: Visual Basic .NET-Verweistypen
Wie Sie in Kapitel 2, »Objektorientierte Programmierung in Visual Basic .NET«, erfahren haben, ist
ein Objekt eine Instanziierung einer Klasse, und eine Object-Variable ist eine Verweisvariable, die
einen Zeiger auf das eigentliche Objekt enthält. Die Object-Variable selbst belegt exakt 4 Bytes, da es
sich um einen Zeiger auf einen Speicherbereich handelt, in dem das Objekt enthalten ist.
Bei der Erstellung einer Verweisvariable wird diese auf Null gesetzt. Aufgrund dieser Tatsache müssen
Sie sicherstellen, dass der Variablen tatsächlich ein Objekt zugewiesen wird, bevor Sie die Variable
verwenden. Betrachten Sie folgendes Beispiel:
Sub main()
Dim oMyObject As Object
MessageBox.Show(oMyObject.GetType.ToString)
End Sub
Der Compiler wird Code wie diesen nicht beanstanden. Wenn dieser Code jedoch ausgeführt und der
Versuch unternommen wird, den Variablentyp auszugeben, stürzt das Programm mit der in
Abbildung 4.2 gezeigten Fehlermeldung ab.
Abbildung 4.2: Der Zugriff auf eine Variable mit einem
Nullverweis führt zu einem Laufzeitfehler
Der String-Datentyp ist eine Sequenz aus (16-Bit) Doppelbyte-Unicode-Zeichen. Die Codes für Unicode-Zeichen reichen von 0 bis 65.535. Die ersten 128 (0-127) Zeichen des Unicode-Zeichensatzes
entsprechen dem ASCII-Zeichensatz – den Buchstaben und Symbolen einer US-amerikanischen
Tastatur. Die zweiten 128 Zeichen (128-255) repräsentierten Sonderzeichen wie z.B. Buchstaben aus
lateinischen Alphabeten, Akzentzeichen, Währungssymbole und Brüche. Die übrigen Zeichen werden
für verschiedene Symbole verwendet, z.B. für weltweit gültige Textzeichen, diakritische Zeichen und
mathematische sowie technische Symbole.
Datentypenfeatures
Visual Basic .NET verfügt über verschiedene Features, die die Programmierung erleichtern. Hierzu zählen beispielsweise eine starke Typisierung, Typensicherheit und Datenerweiterung. Das beste Feature ist
jedoch wahrscheinlich die System.Object-Klasse, von der alle weiteren Klassen abgeleitet werden.
Visual Basic .NET-Datentypen und -Features
Microsoft Corporation: Microsoft SQL Server 2000 Systemverwaltung - Original Microsoft Training: Examen 70-228. ISBN: 3-86063-919-6. Microsoft Press 2001
119
Die System.Object-Klasse
Fast jede moderne Programmiersprache verfügt über eine Art Laufzeitbibliothek, die häufig genutzte
Dienste bereitstellt und Zugriff auf die zugrunde liegende Hardware, das Betriebssystem und den
Dateispeicher bietet. In Kapitel 2 haben Sie erfahren, dass die Common Language Runtime (CLR)
sich aus einer hierarchischen Struktur von Namespaces zusammensetzt. Den Stamm dieser Struktur
bildet der System-Namespace, der verschiedene Objekte, z.B. vordefinierte Typen wie Ganzzahlen,
Zeichenfolgen und Klassen beinhaltet. (Der in Kapitel 2 verwendete System.Windows.Forms-Namespace wird vom System-Namespace vererbt.)
Alle gemeinsamen vordefinierten Typen können in einer beliebigen vom .NET Framework unterstützten Sprache verwendet werden. Sämtliche System-Klassen sind in Mscorlib.dll enthalten und können
von allen .NET-Anwendungen verwendet werden. Sie können diese Klassen als solche nutzen oder
eigene Klassen von diesen ableiten.
Den Stamm aller Klassen (geerbte Klassen oder eigene Klassen) bildet die System.Object-Klasse. In
Visual Basic .NET werden alle Elemente implizit von System.Object abgeleitet. Die System.ObjectKlasse ist die ultimative Superklasse aller Klassen im .NET Framework – diese Klasse ist die einzige
Klasse, die nicht von einem anderen Objekttyp abgeleitet wird. Alle weiteren Objekttypen müssen entweder explizit oder implizit zur Unterstützung (Vererbung von) exakt einem anderen Objekttyp deklariert werden. De facto ist es in Visual Basic .NET unmöglich, eine Klasse zu verwenden, die nicht von
System.Object erbt. Dies stellt sicher, dass jedes Objekt in Visual Basic .NET die Basisfunktionalität
von System.Object erbt.
Sämtliche der in System.Object definierten Methoden stehen in allen Unterklassen und damit auch
allen Objekten im System zur Verfügung. Die System.Object-Klasse (und damit auch jede andere
Klasse) verfügt über die in Tabelle 4.3 aufgeführten sechs Basismethoden.
Object.Method
Zugriff
Beschreibung
Equals
Public
Erwartet als Parameter ein weiteres Objekt und gibt einen booleschen Wert True/
False zurück, der angibt, ob zwei Objekte gleichwertig sind.
GetHashCode
Public
Gibt einen ganzzahligen Hashcode zurück, der den Objektwert repräsentiert.
Dieser Code wird üblicherweise als Schlüssel verwendet, wenn das Objekt einer
Auflistung hinzugefügt wird. Zwei identische Objekte sollten denselben Code
generieren.
Finalize
Protected
Die CLR ruft die Finalize-Methode eines Objekts auf, um anzuzeigen, dass das
Objekt für die Zerstörung vorgesehen ist. Diese Methode löst nichts aus und wird
durch die Klasse überschrieben.
MemberwiseClone
Protected
Erstellt eine Schattenkopie des Objekts.
GetType
Public
Gibt eine Instanz von System.Type zurück, um mithilfe von Metadaten Objektinformationen abzurufen.
ToString
Public
Gibt eine Zeichenfolgendarstellung des Objekts zurück. Die Zeichenfolge ist nicht
formatiert und wird meistens durch die implementierende Klasse überschrieben.
Tabelle 4.3: Grundlegende Visual Basic .NET-Klassenmethoden
Wenn Sie sich Abbildung 3.4 ansehen, erkennen Sie, dass weder die Finalize- noch die MemberwiseClone-Methode in der IntelliSense-Liste angezeigt wird. (Die Equals-, GetHashCode- und ToStringMethoden sind verfügbar, werden jedoch nicht angezeigt.) Diese Methoden fehlen, da sie in der
System.Object-Klasse mit dem Zugriffsmodifizierer Protected definiert sind; nur als Public deklarierte
Methoden werden aufgeführt. Wie Sie wissen, kann auf die als Protected definierten Methoden nur
120
Microsoft Corporation: Microsoft SQL Server 2000 Systemverwaltung - Original Microsoft Training: Examen 70-228. ISBN: 3-86063-919-6. Microsoft Press 2001
Kapitel 4
über eine untergeordnete Klasse zugegriffen werden. Wenn Sie eine Klasse von der System.ObjectKlasse ableiten, werden alle fünf Methoden angezeigt.
Abbildung 4.3: Die IntelliSense-Liste zeigt lediglich
die als Public definierten Methoden an
Verwenden wir nun diese Methoden, indem wir den in Abbildung 4.3 gezeigten Code erweitern:
Imports System
Public Module Module1
Dim myObject1 As New System.Object()
Dim myObject2 As New System.Object()
Dim bReslt As Boolean
Public Sub main()
myObject1 = “Hello Visual Basic .NET"
myObject2 = 42
‘What type is this?
MessageBox.Show(myObject1.GetType.ToString)
‘System.String
‘What is the object’s HashCode?
MessageBox.Show(myObject1.GetHashCode.ToString)
‘-1757321832
‘Are the objects equal?
MessageBox.Show(myObject1.Equals(myObject2).ToString) ‘False
myObject1 = myObject2
MessageBox.Show(myObject1.Equals(myObject2).ToString) ‘True
MessageBox.Show(myObject1.ToString)
‘42
End Sub
End Module
ANMERKUNG: Sie müssen jedes Meldungsfeldargument explizit in eine Zeichenfolge konvertieren.
Diese Anforderung ist ein Beispiel für die starke Typisierung in Visual Basic .NET, auf die ich im
weiteren Verlauf dieses Kapitels noch detailliert eingehen werde.
Visual Basic .NET-Datentypen und -Features
Microsoft Corporation: Microsoft SQL Server 2000 Systemverwaltung - Original Microsoft Training: Examen 70-228. ISBN: 3-86063-919-6. Microsoft Press 2001
121
Die GetType-Methode von myObject1 im ersten Meldungsfeld führt zur Ausgabe von System.Object.
Die GetHashCode-Methode führt auf meinem System zur Ausgabe von −1757321832, dieses Ergebnis
kann jedoch auch anders lauten. In einem echten Programm würden wir die GetHashCode-Methode
in einer abgeleiteten Klasse überschreiben, um eine eindeutige Zahl zurückzugeben, die z.B. als
Schlüsselwort in einer Auflistung verwendet werden könnte.
Als Nächstes werden über die Equals-Methode von myObject1 die Objekte myObject1 und myObject2
miteinander verglichen. Dieser Vergleich führt zur Rückgabe von False, da myObject1 und myObject2
nicht nur individuelle Objekte sind, sondern zusätzlich auch unterschiedliche Werte enthalten. Da
diese Variablen den Typ System.Object aufweisen, akzeptieren sie ohne Murren Zeichenfolgen, Zahlen
oder jeden anderen Datentyp.
In der nächsten Codezeile wird myObject1 mit myObject2 gleichgesetzt, sodass beide Objekte
anschließend auf myObject2 verweisen. In der letzten Zeile wird der Wert von myObject1 ausgegeben.
Das letzte Meldungsfeld zeigt an, dass beide Variablen dasselbe Objekt referenzieren – einen Speicherbereich, der den Wert 42 enthält.
Wie bereits erwähnt, ersetzt der Object-Typ den Variant-Datentyp früherer Visual Basic-Versionen und
kann jede Art von Datentyp enthalten, z.B. Zeichenfolgen, Gleitkommawerte oder einen Verweis auf
ein Microsoft Word-Dokument. Obwohl Sie eine Verweisvariable in den meisten Fällen mit einem
spezifischen Datentyp dimensionieren, ist gelegentlich auch eine Variable vom Typ Object erforderlich.
Dies sollte jedoch nur selten der Fall sein. Warum? Weil auch eine als Object deklarierte Variable flexibel genug ist, einen Verweis auf beliebige Objekt- oder Datentypen zu enthalten. Der Aufruf einer
Methode vom Typ Object erzwingt eine späte Bindung (zur Laufzeit), was im Grunde bedeutet, dass
die CLR bei jedem Programmzugriff auf die Object-Variable den Variablentyp bestimmen muss. Dies
verbraucht nicht nur CPU-Zyklen, sondern stellt auch immer eine potenzielle Fehlerquelle dar. Sie
könnten beispielsweise versehentlich eine Object-Variable mit einem Zeichenfolgenwert an eine
Methode übergeben, die eine Ganzzahl erwartet. Fehler wie diese werden erst zur Laufzeit erkannt
und können zu Verwirrung führen, wenn der Benutzer einen Laufzeitfehler erhält.
Aufgrund der starken Typisierung von Visual Basic .NET sollten Sie eine frühe Bindung (zur Kompilierungszeit) erzwingen, indem Sie die Variable mit einem spezifischen Objekttyp dimensionieren. Ist
eine solche Dimensionierung nicht möglich, sollten Sie – wann immer möglich – eine Konvertierung
in einen spezifischen Datentyp vornehmen.
Starke Typisierung
Die starke Typisierung erfordert spezifische Datentypen für jede in einem Programm verwendete
Variable. Stark typisierte Variablen ermöglichen IntelliSense die Anzeige der Variableneigenschaften
und -methoden bei der Arbeit im Editor. Ferner ermöglicht die starke Typisierung auch eine Typprüfung durch den Compiler, wodurch gewährleistet wird, dass Anweisungen mit unzulässigen Datentypen abgefangen werden, bevor sie Laufzeitfehler verursachen können. Schließlich führt die starke
Typisierung auch zu einer schnelleren Codeausführung, da der Compiler keine CPU-Zyklen zur
Bestimmung von Variablentypen belegen und anschließend im Hintergrund keine Typkonvertierung
vornehmen muss. Die starke Typisierung von .NET zwingt den Programmierer, Codefehler zu beseitigen.
In früheren Versionen von Visual Basic stellte der Compiler die primitiven Datentypen zur Verfügung.
Wie Sie aus Kapitel 1, »Visual Basic .NET – der Einstieg«, wissen, werden die primitiven Datentypen
in allen .NET-Sprachen von der CLR bereitgestellt. Der .NET-Sprachcompiler erstellt für die verschiedenen Sprachimplementierungen einen entsprechenden Teilsatz aller verfügbaren Datentypen. Der
.NET-sprachspezifische Teilsatz an Datentypen wird der Klasse System.Type zugeordnet, sodass jeder
.NET-Datentyp in jeder unterstützten Sprache gleich ist – so wird garantiert, dass der in einer .NET-
122
Microsoft Corporation: Microsoft SQL Server 2000 Systemverwaltung - Original Microsoft Training: Examen 70-228. ISBN: 3-86063-919-6. Microsoft Press 2001
Kapitel 4
Sprache geschriebene Code problemlos mit dem Code anderer .NET-Sprachen interagieren kann. Für
diejenigen unter Ihnen, die bisher mit API-Funktionsdeklarationen gearbeitet haben: Die Fummelei
bei der Konvertierung der Datentypen in das erwartete C-Sprachformat hat jetzt ein Ende. Die standardmäßigen .NET-Datentypen erleichtern darüber hinaus die Portierung, sodass Programme (ohne
Neukompilierung) auf einem beliebigen Betriebssystem mit CLR-Unterstützung ausgeführt werden
können.
Typensicherheit
Visual Basic .NET ist eine typensichere Sprache. Sie wissen jetzt, dass Sie auf eine Variable nur über
den mit dieser Variable verknüpften Typ zugreifen können – bei falschen Typzuordnungen meckert der
Compiler. Diese Einschränkung fördert (eine schöne Umschreibung für »erzwingt«) ein gutes Programmdesign. Außerdem werden potenzielle Fehler oder Sicherheitslücken bereits im Keim erstickt,
da das versehentliche oder beabsichtigte Überschreiben einer Variablen nicht möglich ist. Wenn Sie
bei der Variablendeklaration keinen speziellen Datentyp angeben, weist Visual Basic .NET der Variable den Datentyp Object zu. Diese Standardzuweisung ähnelt Visual Basic 6, da dort den nicht spezifizierten Variablen der Datentyp Variant zugeordnet wird.
Visual Basic 6 verfügt über die Option Explicit-Direktive, die eine Deklaration aller Variablen
erzwingt. Visual Basic .NET unterstützt diese und die neue Option Strict-Direktive, wie in Tabelle 4.4
gezeigt.
Direktive
Werte
Beschreibung
Option Explicit
On | Off
Erzwingt die explizite Deklarationen aller Variablen in einem Modul. Diese Direktive ist
standardmäßig aktiviert.
Option Strict
On | Off
Beschränkt implizite Datentypkonvertierungen auf erweiternde Konvertierungen. Auf
diese Weise wird explizit verhindert, dass bei einer Datentypkonvertierung ein Datenverlust auftritt. Ferner ist auch die Konvertierung zwischen numerischen Typen und
Zeichenfolgen unzulässig. Diese Direktive ist standardmäßig deaktiviert.
Tabelle 4.4: Visual Basic .NET-Direktiven zur Typensicherheit
Wenn die Option Strict-Direktive aktiviert ist, müssen alle Variablen eine AS-Klausel zur expliziten
Typdeklaration der Variablen aufweisen. Darüber hinaus kann der &-Operator nicht zum Verketten
von Object-Variablen eingesetzt werden. Es gehört zum guten Ton, die Option Explicit-Directive in
jedem Modul zu verwenden, damit jede Variable über die Dim-, die Private-, die Public- oder die
ReDim-Anweisung explizit deklariert wird – der Compiler erzeugt für jede nicht deklarierte Variable
einen Fehler, wenn Option Explicit aktiviert wurde. Wenn sowohl Option Explicit als auch Option
Strict deaktiviert sind, können Sie nicht deklarierte Variablen verwenden, die dann standardmäßig
mit dem Typ Object definiert werden:
Option Explicit Off
Option Strict Off
myVariable = “Hello Visual Basic .NET"
Neben der Tatsache, dass nicht deklarierte Variablen zu schwer auffindbaren Programmfehlern führen
können, wird das Lesen des Codes zu einer Herausforderung. Alle nicht deklarierten Variablen zu verfolgen ist äußerst schwierig. Sofern keine wirklich guten Gründe vorliegen – und mir fällt eigentlich
keiner ein –, sollten beide Direktiven immer aktiviert werden. Stellen Sie sich die Direktiven als eine
Art Gratisversicherung vor.
Visual Basic .NET-Datentypen und -Features
Microsoft Corporation: Microsoft SQL Server 2000 Systemverwaltung - Original Microsoft Training: Examen 70-228. ISBN: 3-86063-919-6. Microsoft Press 2001
123
Hier ein weiteres Beispiel dafür, was passieren kann, wenn ein Datentyp nicht deklariert wird. Wenn
Sie Option Strict deaktivieren, funktioniert der folgende Code prima.
Dim myVariable = “Hello Visual Basic .NET”
MessageBox.Show(myVariable & “ is type “ & _
myVariable.GetType.ToString())
Beachten Sie, dass die Dim-Anweisung zur Deklaration von myVariable keine AS-Klausel enthält,
daher wird myVariable der Standardtyp Object zugewiesen, d.h., die Variable kann einen beliebigen
Datentyp enthalten. Das Meldungsfeld zeigt die Inhalte der Variable sowie den zugehörigen Datentyp
an, wie dargestellt in Abbildung 4.4.
Abbildung 4.4: In dieser Abbildung enthält myVariable eine Zeichenfolge
Wir könnten der gleichen Variable, die jetzt eine Zeichenfolge enthält, auch einen Gleitkommawert
zuweisen.
myVariable = 123.456
MessageBox.Show(myVariable & “ is type “ & _
myVariable.GetType.ToString())
Das in Abbildung 4.5 dargestellte Meldungsfeld zeigt, dass myVariable jetzt einen Gleitkommawert
enthält.
Abbildung 4.5: In dieser Abbildung enthält myVariable einen Gleitkommawert
Sie wundern sich jetzt vielleicht, warum dieser Code zulässig ist, obwohl Visual Basic .NET typensicher sein soll. Die Anwort lautet: Dieser Code wird erst zulässig, wenn Sie Option Explicit ausdrücklich deaktivieren.
Sie können immer noch dieselben Fehler wie in Visual Basic 6 erzeugen, wenn Sie die Direktive
Option Explicit deaktivieren. Sie könnten beispielsweise oMyObject deklarieren, später im Code
jedoch eine Variable namens MyObject verwenden. Sehen Sie sich das folgende Codefragment an:
Sub Main()
Dim oMyObject As Object
oMyObject = “Hello Visual Basic .NET!"
MessageBox.Show(MyObject)
End Sub
Der Programmierer wollte wahrscheinlich auch im Meldungsfeld eigentlich oMyObject schreiben. (Bei
Variablennamen schleichen sich schnell Tippfehler ein.) Bei Programmausführung erwartet er/sie also,
dass ein »Hello Visual Basic .NET!«-Meldungsfeld erscheint. Da MyObject jedoch nicht existiert,
erstellt Visual Basic .NET ein leeres Meldungsfeld. Durch die Aktivierung von Option Strict und
Option Explicit (Standardeinstellung) ersparen Sie sich Probleme und sind immer auf der sicheren
Seite.
124
Microsoft Corporation: Microsoft SQL Server 2000 Systemverwaltung - Original Microsoft Training: Examen 70-228. ISBN: 3-86063-919-6. Microsoft Press 2001
Kapitel 4
Bestimmen des Variablentyps
Wie bereits gesagt, erhält jeder Datentyp in Visual Basic .NET einen Standardwert, wenn Sie eine
Variable dimensionieren. Angenommen, ein Programm dimensioniert eine Object-Variable und eine
Integer-Variable, wie nachfolgend gezeigt:
Dim myObject1 As New System.Object()
Dim myInteger1 As New Integer()
MessageBox.Show(myObject1.ToString)
MessageBox.Show(myInteger1.ToString)
’System.Object
‘0
Eine Standardimplementierung der ToString-Methode der Object-Variable gibt den vollqualifizierten
Namen der Objektklasse zurück. Beachten Sie, dass hier nicht (wie bei der Integer-Variable) der Wert
der Variablen ausgegeben wird. Obwohl Sie die ToString-Methoden Ihres Objekts in der Regel überschreiben, eignen sich die integrierten Methoden doch insbesondere zum Debuggen.
Werttypvariablen erben von der Object.ValueType-Klasse. Die Object.ValueType-Klasse überschreibt
die Objektmethode ToString, um den Variablenwert anzuzeigen. Dies wird durch das vorstehende Beispiel verdeutlicht, in dem anstelle des Variablentyps der Wert der ganzzahligen Variablen (0) ausgegeben wird.
Über die integrierte Funktion TypeName kann folgendermaßen der Objekttyp bestimmt werden:
MessageBox.Show(TypeName(myObject1))
‘Object
MessageBox.Show(TypeName(myInteger1)) ‘Integer
Eine typische Visual Basic .NET-Zuweisung
Sehen wir uns ein weiteres Beispiel zur Verdeutlichung des Typsystems an. Sie werden sich schon bald
der Herausforderung gegenübersehen, dass Sie herausfinden müssen, nach welchem Datentyp die
CLR in einer Zuweisung sucht. Sie könnten beispielsweise einem aus Windows.Forms.Form erstellten
Formular ein Textfeldsteuerelement mit dem Namen txtName hinzufügen, um einen Mitarbeiternamen anzuzeigen. Sie könnten festlegen, dass sich die Hintergrundfarbe des Textfeldes ändert, wenn der
Benutzer dies bearbeitet. Der Code könnte so aussehen:
txtName.BackColor = “yellow"
Unglücklicherweise weiß der Visual Basic .NET-Editor, dass dieser Code unzulässig ist und hat auch
keine Hemmungen, Ihnen dies mitzuteilen, wie aus Abbildung 4.6 hervorgeht. Das Problem besteht
darin, dass die BackColor-Methode des Textfeldes txtName einen System.Drawing.Color-Typ erwartet,
und Sie waren so verwegen, eine Zeichenfolge zu übergeben.
Abbildung 4.6: Der Visual Basic .NET-Editor
warnt Sie vor falschen Datentypzuordnungen
Visual Basic .NET-Datentypen und -Features
Microsoft Corporation: Microsoft SQL Server 2000 Systemverwaltung - Original Microsoft Training: Examen 70-228. ISBN: 3-86063-919-6. Microsoft Press 2001
125
Überlegen Sie kurz, was Sie eigentlich möchten. Genau: Sie versuchen, die BackColor-Eigenschaft des
Textfeldes zu setzen. Sie können anhand der IDE-Meldung sehen, dass die BackColor-Eigenschaft
einen System.Drawing.Color-Datentyp erwartet, keine Zeichenfolge. Der Visual Basic .NET-Compiler kann die Konvertierung einer Zeichenfolge in einen System.Drawing.Color-Datentyp nicht
erzwingen, und das möchten wir auch gar nicht.
Jeder Datentyp im .NET Framework legt verschiedene Eigenschaften und Methoden offen. Sie können
das oben geschilderte Problem lösen, indem Sie diese Eigenschaften und Methoden dazu verwenden,
die Zeichenfolge in den System.Drawing.Color-Datentyp zu konvertieren, den die BackColorEigenschaft erwartet. Diese Aufgabe wird mit dem folgenden Code sauber gelöst. Die Color-Klasse
stellt eine Methode bereit, welche die explizite Konvertierung für uns durchführt. Wenn Sie
System.Drawing.Color eingeben, präsentiert uns die IDE eine reichhaltige Farbauswahl. An dieser
Stelle wählen Sie einfach den Wert Yellow aus.
txtName.BackColor = System.Drawing.Color.Yellow
Die System.Drawing.Color-Klasse verfügt also über verschiedene Farbkonstanten wie z.B. Yellow, die
Sie setzen können. Neben der Farbeigenschaft verfügt die System.Drawing.Color-Klasse über die nützliche Methode FromName. Wenn Sie die vordefinierten Farbkonstanten kennen, können Sie mithilfe
der FromName-Methode eine Zeichenfolge mit der gewünschten Farbe übergeben.
txtName.BackColor = System.Drawing.Color.FromName("blue")
Dieses Beispiel der Farbenzuweisung verdeutlicht ein typisches Zuweisungsproblem, mit dem vor
allem Visual Basic .NET-Einsteiger zu kämpfen haben. Wenn man nicht weiß, wie sich das Problem
lösen lässt, kann dies einigen Frust hervorrufen. Und obwohl das Problem auf zwei Arten gelöst werden kann, erscheint Ihnen der Code vielleicht trotzdem eher wie Klingonisch. Darüber hinaus fragen
Sie sich vielleicht gerade, wo Sie denn all diese Klassen finden, ganz zu schweigen davon, wie sie
zueinander in Beziehung stehen.
Keine Bange. Im nächsten Beispiel werde ich detailliert auf das .NET Framework eingehen, und Sie
werden schon bald wissen, wie Sie die benötigten Klassen problemlos auffinden. Ferner haben uns die
Sprachdesigner das Tool WinCV zur Verfügung gestellt, das eine hierarchische Sicht liefert, mit der das
Auffinden von Klassen, Methoden oder Prozeduren kinderleicht wird. (Dieses Tool wird in
Kapitel 5, »Untersuchen des .NET-Klassenframeworks mithilfe von Dateien und Zeichenfolgen«,
vorgestellt).
Datenerweiterung
Wie schon erwähnt, beschränkt die Direktive Option Strict implizite Datentypkonvertierungen auf
erweiternde Konvertierungen. Diese Einschränkung verbietet Datentypkonvertierungen, bei denen ein
Datenverlust auftreten würde und verhindert außerdem Konvertierungen zwischen numerischen
Typen und Zeichenfolgen.
Bei einer erweiternden Konvertierung wird der Wert in einen Typ geändert, der Daten gleichen oder
größeren Umfangs aufnehmen kann. Tabelle 4.5 zeigt die standardmäßigen erweiternden Datentypkonvertierungen.
Datentyp
Erweiterung auf folgende Datentypen
Byte
Byte, Short, Integer, Long, Decimal, Single, Double
Short
Short, Integer, Long, Decimal, Single, Double
Integer
Integer, Long, Decimal, Single, Double
Long
Long, Decimal, Single, Double
126
Microsoft Corporation: Microsoft SQL Server 2000 Systemverwaltung - Original Microsoft Training: Examen 70-228. ISBN: 3-86063-919-6. Microsoft Press 2001
Kapitel 4
Datentyp
Erweiterung auf folgende Datentypen
Decimal
Decimal, Single, Double
Single
Single, Double
Double
Double
Char
String
Beliebiger Typ
Object
Tabelle 4.5: Erweiternde Datenkonvertierungen
Konvertierungen von Integer nach Single oder von Long oder Decimal nach Single oder Double können zu einem Genauigkeits-, aber nicht zu einem Größenverlust führen. Daher führt eine solche Konvertierung insofern nicht zu einem Informationsverlust, als ein Wert in einem größeren Bereich
gespeichert wird. Umgekehrt gilt dies jedoch nicht. Sehen Sie sich das folgende Codefragment an:
Dim iInteger As Integer = 10
Dim lLong As Long
lLong = iInteger
iInteger = lLong
'Dies funktioniert prima; wir können einen iInteger-Wert
' unbesorgt in einen lLong-Wert konvertieren.
'Dies funktioniert nicht; eine Konvertierung von lLong
' nach iInteger ist nicht ohne weiteres möglich.
Wenn Sie dieses Programm ausführen, erhalten Sie eine Fehlermeldung, in der Sie darüber informiert
werden, dass Option Strict implizite Konvertierungen von Long nach Integer nicht zulässt.Option
Strict schützt uns auch hier vor Fehlern, die später nur schwer zurückverfolgt werden können. Natürlich können nach einer Deaktivierung von Option Strict diese impliziten Konvertierungen durchgeführt werden; Sie sollten davon jedoch absehen. Es passiert schnell, dass versehentlich eine Zahl, die
größer ist als Integer in eine Variable namens iInteger gepackt wird. Und da dieser Fehler nur zur Laufzeit auftritt, finden Sie ihn möglicherweise erst dann, wenn das Programm bereits im Umlauf ist.
Option Strict stellt sicher, dass diese Art von Überlauffehlern in Visual Basic .NET nicht auftritt.
Jede Konvertierung, die nicht zu einem Genauigkeitsverlust führt (eine einschränkende Konvertierung), wird keine Ausnahme erzeugen. (Eine Ausnahme ist eine Art Fehler. Ausnahmen werden in
Kapitel 7, »Fehlerbehandlung und Debugging«, ausführlich erläutert.) Sie können weiterhin die
Inhalte einer Long-Variable einer Integer-Variable zuweisen, indem Sie eine Long-Variable per Casting
explizit in eine Integer-Variable umwandeln. Natürlich geht der Compiler davon aus, dass Sie wissen,
was Sie tun. Der Begriff Casting bezeichnet die Erzwingung einer Umwandlung in einen vorgegebenen
Typ. In einigen Programmierzirkeln wird das Casting auch als »Feindliche Typumwandlung« bezeichnet. Spezielle cast-Schlüsselwörter erzwingen die Umwandlung in primitive Typen. Das allgemeine
Schlüsselwort für das Casting, CType, wandelt einen Ausdruck in einen beliebigen Typ um. Existiert
keine Konvertierung vom Ausdrucktyp in den angegebenen Typ, tritt ein Kompilierungsfehler auf.
Andernfalls wird der durch die Konvertierung erhaltene Wert als Ergebnis zurückgegeben.
CastAusdruck ::= CType ( Ausdruck , TypeName ) |
CastZiel ( Ausdruck )
CastZiel ::=
CBool | CByte | CChar | CDate | CDec |
CDbl | CInt | CLng | CObj | CShort | CSng | CStr
Wir könnten beispielweise die Inhalte unserer Long-Variable folgendermaßen in eine Integer-Variable
umwandeln:
iInteger = CType(lLong, Integer)
Hier gibt es aber ein weiteres Problem. Angenommen, der Wert von Long ist größer als der maximal in
einer Integer-Variable speicherbare Wert. Bei der Programmausführung werden die Werte berechnet,
Visual Basic .NET-Datentypen und -Features
Microsoft Corporation: Microsoft SQL Server 2000 Systemverwaltung - Original Microsoft Training: Examen 70-228. ISBN: 3-86063-919-6. Microsoft Press 2001
127
und plötzlich liegt ein Wert vor, der größer ist als angenommen. Anschließend versuchen wir auf folgende Weise, den Long-Wert in einen Integer-Wert umzuwandeln:
Dim iInteger As Integer
Dim lLong As Long = 2147483648 ‘Dieser Wert liegt um 1 höher als der
‘ maximal zulässige Ganzzahlenwert (2.147.483.647)
iInteger = CType(lLong, Integer)
Ups! Wir erhalten einen Laufzeitfehler. Sie können diesen Fehler nicht vorhersehen, da Long immer
einen größeren Wert enthalten kann als Integer. Dieser Fehler wird nur zur Laufzeit sichtbar, wie dargestellt in Abbildung 4.7.
Abbildung 4.7: Dieser Fehler kann nicht vorausgesehen
werden
Die Integer-Variable wurde nicht explizit initialisiert, daher weist der Compiler ihr den Standardwert 0
zu. Der Code initialisiert anschließend die Long-Variable lLong mit einem Wert, der über dem Maximalwert der Ganzzahl liegt. Die CLR erkennt, dass der Wert zu groß für iInteger ist und erzeugt die in
Abbildung 4.7 gezeigte Ausnahme.
Ein Laufzeitfehler wie dieser gehört zu den schlimmsten Fehlern. Ein Entwurfszeitfehler kann leicht
behoben werden – genauer gesagt: Das Programm kann vor der Beseitigung des Fehlers gar nicht
kompiliert und ausgeführt werden –, aber ein Laufzeitfehler ist immer heimtückisch. Der fehlerverursachende Code ist möglicherweise in einer tiefen, dunklen Ecke Ihres Programmcodes verborgen und
wird zu selten ausgeführt, um beim Testen als fehlerhaft aufzufallen. Oder – je nach Ereignisreihenfolge – einer Variablen wurde in unvorhersehbarer Weise ein zu großer Wert zugewiesen. Aus all diesen Gründen ist die starke Typisierung von Visual Basic .NET ein wirklicher Vorteil. Sie müssen einen
Datentyp einem ähnlichen Datentyp zuordnen, oder Sie müssen eine explizite Umwandlung durchführen und selbst die Verantwortung für eventuell auftretende Datenverluste übernehmen.
Und die Moral von der Geschichte: Deaktivieren Sie niemals die Direktiven Option Strict oder Option
Explicit, und stellen Sie sicher, dass ein großer Variablentyp nicht in einen kleineren Typ umgewandelt
wird, sofern keine guten Gründe hierfür vorliegen. Und selbst wenn Sie einen guten Grund haben sollten, müssen Sie sicherstellen, dass der konvertierte Wert niemals die Speicherkapazität des kleineren
Typs übersteigt.
Es mag überraschend erscheinen, dass eine Konvertierung von einem abgeleiteten (geerbten) Typ in
einen der Basistypen als erweiternde Konvertierung betrachtet wird. Diese Konvertierung ist möglich,
da der abgeleitete Typ alle Member des Basistyps enthält, d.h., die Konvertierung führt dazu, dass der
Basistyp vollständig aufgefüllt wird. Der Basistyp verfügt jedoch nicht über alle Member des abgeleiteten Typs, daher wird der abgeleitete Typ bei der Konvertierung von einem Basistyp in einen abgeleiteten Typ nicht vollständig aufgefüllt – die Konvertierung wird als einschränkend betrachtet.
In unseren Programmen können wir also bedenkenlos erweiternde Konvertierungen einsetzen. Erweiternde Konvertierungen sind immer erfolgreich und können implizit durchgeführt werden. Eine einschränkende Konvertierung dagegen kann einen Informationsverlust nach sich ziehen. Wie wir
gesehen haben, verläuft eine einschränkende Konvertierung nicht immer erfolgreich und kann zu
Laufzeitfehlern führen. Und genau aus diesem Grund lässt der Compiler keine impliziten einschränkenden Konvertierungen zu – diese Art der Konvertierung müssen Sie explizit durchführen.
128
Microsoft Corporation: Microsoft SQL Server 2000 Systemverwaltung - Original Microsoft Training: Examen 70-228. ISBN: 3-86063-919-6. Microsoft Press 2001
Kapitel 4
Garbage Collection: Weg mit den Objekten
Sie haben bereits erfahren, wie Objekte erstellt und instanziiert werden. Sie wissen auch, wie Sie diese
los werden, wenn sie nicht länger benötigt werden. In Visual Basic 6 gab es zwei Möglichkeiten, den
von nicht mehr benötigten Objekten belegten Speicher wieder freizugeben. Die bequeme Methode
war, darauf zu warten, dass das Objekt seinen Gültigkeitsbereich überschreitet. Die zweite und professionellere Methode bestand darin, SET myObject = Nothing zu verwenden.
Da Visual Basic 6 auf COM basiert, wurde für jede neue Objektinstanz bzw. für jeden neuen Verweis
auf ein vorhandenes Objekt ein interner Verweiszähler um 1 erhöht. Sobald der Verweis auf das
Objekt freigegeben wurde, erniedrigte sich der Verweiszähler um 1. Sobald keine Objektverweise
mehr vorhanden waren, wurde das Objekt beendet, der belegte Speicher und alle verwendeten Ressourcen wurden wieder freigegeben. Hierzu wurde in vorhersagbarer Weise das Class_TerminateEreignis aufgerufen. Wir wussten sicher, wann dieses Ereignis eintreten würde und konnten jeglichen
Bereinigungscode, z.B. zum Freigeben von Datenbankverbindungen, in diesem Ereignis platzieren.
Diese Form der klaren Objektbeendigung wird auch als determinististische Finalisierung bezeichnet.
Visual Basic 6-Programmierer wussten stets ganz genau, wann ein Objekt freigegeben wurde.
Der Stack und der verwaltete Heap
Wenn Sie ein Visual Basic .NET-Programm schreiben, reserviert das Betriebssystem exklusiv für die
Programmverwendung einen Speicherblock. Die Anwendung nutzt die zahlreichen Speicherbereiche
in diesem Speicherblock, um die verschiedenen Programmobjekte zu speichern. Der Programmspeicher weist ein Codesegment (die Anweisungen für den Computer) sowie ein Datensegment auf (für
speicherinterne Objekte, Variablen und anderen temporären Speicher). Das Datensegment wird weiter unterteilt in den Stack (Wertvariablen) und den Heap (Verweisvariablen). Sie sehen also, dass es
wichtig ist, den Unterschied zwischen Wert- und Verweisvariablen zu kennen. Die Art der Speicherung und Freigabe nach Verwendung unterscheidet sich für Wert- und Verweisvariablen. Wenn Sie
eine klare Vorstellung davon haben, wie Verweisvariablen gespeichert werden, können Sie die Codeleistung verbessern. Abbildung 4.8 skizziert die Speicherzuordnung für ein Programm.
Code
Stack
Heap
Daten
Abbildung 4.8: Speicherzuordnung für ein Programm
Wertobjekte wie z.B. Ganzzahlen werden im Stack gespeichert. Der Stack speichert darüber hinaus
Daten, die an Funktionen und Methoden übergeben werden. Je mehr Elemente im Stack platziert werden (z.B. bei der Übergabe mehrerer Parameter an eine Prozedur) desto näher rücken Stack und Heap
zusammen. Der Compiler kann die Größe des Stacks bestimmen, da er die genaue Größe der in Prozeduren, Funktionsaufrufen usw. verwendeten Werttypen kennt. Sobald eine Wertvariable den Gültigkeitsbereich überschreitet, wird der belegte Speicher sofort freigegeben, der Stack wird verkleinert.
Dies gilt nicht für die im verwalteten Heap gespeicherten Verweisvariablen. In Visual Basic 6 konnte
über Set myObject = Nothing Speicher freigegeben werden, Visual Basic .NET arbeitet jedoch in anderer Weise. Sobald in Visual Basic .NET ein Objekt den Gültigkeitsbereich überschreitet, wird es intern
zum Löschen markiert. Einige Zeit später untersucht ein Low-Level-Hintergrundtread den Heapspeicher und prüft, welche Objekte gefahrlos freigegeben werden können. Um die Speicherverwaltung
muss sich ab sofort nicht mehr der Programmierer, sondern das System kümmern. Diese Form der
Speicherverwaltung wird als nicht deterministische Finalisierung bezeichnet.
Visual Basic .NET-Datentypen und -Features
Microsoft Corporation: Microsoft SQL Server 2000 Systemverwaltung - Original Microsoft Training: Examen 70-228. ISBN: 3-86063-919-6. Microsoft Press 2001
129
Während das Setzen eines Objekts Nothing in Visual Basic 6 zur sofortigen Speicherfreigabe führte,
kann dieser Prozess in Visual Basic .NET etwas Zeit in Anspruch nehmen. In einigen Fällen können
ein paar Minuten vergehen, bevor der Garbage Collector seine Runde macht und nicht mehr benötigte
Objekte aus dem verwalteten Heap entfernt. Das Gute daran ist, dass diese Verzögerung häufig zu
einer Leistungsverbesserung führt. Statt CPU-Zyklen für die Freigabe nicht mehr benötigter Objekte
zu verbrauchen, wartet das System so lange, bis die Anwendung sich im Leerlauf befindet – wodurch
sich die Speicherbereinigung nicht negativ auf den Benutzer auswirkt.
Sie können die Garbage Collection programmgesteuert auslösen, indem Sie System.GC.Collect aufrufen, aber diese Methode wird eher selten eingesetzt, z.B. in Fällen, in denen sofort viele große Objekte
freigegeben werden müssen. Die meisten Programme machen keinen Gebrauch von dieser Methode.
Der Stack rückt näher an den Heap heran, wenn er anwächst (und umgekehrt). Treffen sich beide
Speicherbereiche, verfügt die Anwendung nicht mehr über genügend Speicher – und dann ist es nur
noch eine Frage der Zeit, bis das Programm abstürzt. Bei der komplexen Programmierung waren
Abstürze dieser Art stets ein Problem, die erweiterte .NET-Runtime sorgt mit ihrem erweiterten Speicherreservierungsalgorithmus dafür, dass diese Situation erst gar nicht eintritt.
Fazit
Wie Sie erfahren haben, ist die starke Typisierung für alle Variablen in Visual Basic .NET verbindlich.
Über diese Richtlinie wird sichergestellt, dass wir immer genau wissen, welcher Datentyp sich in jeder
einzelnen Variable befindet. Dies reduziert die Fehlerquellen und optimiert den Speicher, indem nur
der jeweils kleinste Datentyp für eine bestimmte Aufgabe gewählt wird. Statt mit dem Datentyp Object
ein Zeichen zu speichern, können wir einen passenden Datentyp für jede Aufgabe verwenden. Meiner
Meinung nach ist dieser Ansatz einfach der sinnvollste.
Verweisdatentypen enthalten einen Zeiger auf einen bestimmten Speicherbereich. Der referenzierte
Speicherbereich kann ein großes Objekt, eine Zeichenfolge oder andere Daten enthalten. Es kann
mehrere Verweisdatentypen geben, die auf denselben Speicherbereich verweisen. Änderungen im
Speicherbereich spiegeln sich in allen Variablen wider, die auf diesen Speicherbereich verweisen.
Werttypen dagegen sind primitive Typen, die einen Datentyp enthalten, der im Voraus bekannt ist, z.B.
eine Ganzzahl. Da eine Ganzzahl immer 4 Bytes umfasst, kann die CLR einen 4 Byte großen Speicherbereich zur Speicherung eines Wertes reservieren. Mit anderen Worten: Es besteht kein Grund,
auf einen anderen Speicherbereich zu verweisen, der eine Variable unbekannter Größe enthält.
Die Variablen in Visual Basic .NET sind stark typisiert; jede Variable muss mit der As-Klausel dimensioniert werden, z.B. Dim iInteger AS integer. Auch wenn einige Programmierer dieses Konzept als
unnötig starr empfinden, setzen viele andere eine starke Typisierung jedoch mit einer guten Programmierung gleich.
130
Microsoft Corporation: Microsoft SQL Server 2000 Systemverwaltung - Original Microsoft Training: Examen 70-228. ISBN: 3-86063-919-6. Microsoft Press 2001
Kapitel 4
Herunterladen