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