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

 <<   zurück
Visual Basic 2005 von Andreas Kühnel
Das umfassende Handbuch
Buch: Visual Basic 2005

Visual Basic 2005
1.233 S., mit 2 CDs, 59,90 Euro
Rheinwerk Computing
ISBN 3-89842-585-1
gp Kapitel 5 Das Klassendesign (Teil 2)
  gp 5.1 Statische Klassenkomponenten
    gp 5.1.1 Die Realisierung eines Objektzählers
    gp 5.1.2 Zugriff auf statische Komponenten
    gp 5.1.3 Statische Klassenvariable in der Klasse »Circle«
    gp 5.1.4 Klassenspezifische Methoden
    gp 5.1.5 Statische Methoden in der Klasse »Circle«
    gp 5.1.6 Statische Klasseninitialisierer
    gp 5.1.7 Zusammenfassung
  gp 5.2 Delegaten
    gp 5.2.1 Einführung in das Prinzip der Delegaten
    gp 5.2.2 Zusammenfassung der Arbeitsschritte
    gp 5.2.3 Vereinfachter Aufruf eines Delegaten
  gp 5.3 Ereignisse eines Objekts
    gp 5.3.1 Ergänzung eines Ereignisses in einer Ereignisquelle
    gp 5.3.2 Die Behandlung eines Ereignisses im Ereignisempfänger
    gp 5.3.3 Ereignisse mit Übergabeparameter
    gp 5.3.4 Die Handles-Klausel
    gp 5.3.5 Die Registrierung eines Ereignishandlers mit »AddHandler«
    gp 5.3.6 Zusammenfassung
  gp 5.4 Strukturen – eine Sonderform der Klassen
    gp 5.4.1 Die Definition einer Struktur
    gp 5.4.2 Initialisieren einer Struktur
    gp 5.4.3 Ereignisse in einer Struktur
    gp 5.4.4 Änderung der Klasse »Circle«
    gp 5.4.5 Zusammenfassung der Unterscheidungsmerkmale Klasse – Struktur
  gp 5.5 Enumerationen (Aufzählungen)
    gp 5.5.1 Alle Mitglieder einer Aufzählung durchlaufen
  gp 5.6 Referenz- und Wertetypen
    gp 5.6.1 Typumwandlung mit Boxing
    gp 5.6.2 Die Unboxing-Konvertierung
    gp 5.6.3 Zusammenfassung
  gp 5.7 Namensräume (Namespaces)
    gp 5.7.1 Zugriff auf Namespaces
    gp 5.7.2 Die »Imports«-Anweisung
    gp 5.7.3 Aliasnamen zur Vermeidung von Mehrdeutigkeiten
    gp 5.7.4 Aufrufe mit »Global« umleiten
    gp 5.7.5 Namespaces festlegen
    gp 5.7.6 Zusammenfassung

Kapitel 5 Das Klassendesign (Teil 2)


Galileo Computing

5.1 Statische Klassenkomponenten  downtop

In der Klasse Circle sind bisher drei Eigenschaften definiert, die den Zustand eines Objekts dieses Typs beschreiben:

gp  XKoordinate
gp  YKoordinate
gp  Radius

Jede Instanz der Klasse Circle reserviert für ihre Daten einen eigenen Speicherbereich, der vollkommen unabhängig von den Daten anderer Objekte ist – selbst wenn diese typgleich sind. Auch alle bisher implementierten Methoden sind an Objekte gebunden, denn Sie arbeiten mit den Zustandsdaten des Objekts.

Was ist aber, wenn Felder oder Methoden benötigt werden, die für alle Objekte der Klasse Circle gleichermaßen gültig sein sollen, also ohne feste Bindung an ein bestimmtes, konkretes Objekt? Stellen Sie sich vor, Sie beabsichtigten, in der Klasse Circle einen Zähler namens CountCircles zu implementieren, der die Aufgabe hat, die Gesamtanzahl der Kreisobjekte festzuhalten. Ein solcher Zähler entspricht der Forderung nach einer allgemeinen, objektunabhängigen Funktionalität.

Was jedoch benötigt wird, sind Felder und Methoden ohne Bindung an ein konkretes Objekt. Komponenten, die dieser Vorgabe entsprechen, werden auch als Klassenvariablen bzw. Klassenmethoden, oder – ganz allgemein – als statische Mitglieder bezeichnet.


Tabelle 5.1     Begriffe der Klassenkomponenten

Begriff Beschreibung
Instanzvariablen Objektdaten (Felder), die einer bestimmten Klasseninstanz eigen sind
Klassenvariablen Felder, die jedem Objekt einer Klasse gleichermaßen zur Verfügung stehen
Instanzmethoden Methoden, deren Ausführung an eine konkrete Instanz der Klasse gebunden ist
Klassenmethoden Methoden, die das Verhalten einer Klasse ganz allgemein beschreiben, unabhängig von einem konkreten Objekt


Galileo Computing

5.1.1 Die Realisierung eines Objektzählers  downtop

Der Objektzähler soll nun implementiert werden. Bitte beachten Sie, dass es sich um einen Objekt- und nicht um einen Referenzzähler handelt. Ein Objektzähler kennt die Gesamtanzahl aller konkreten Objekte, ein Referenzzähler hingegen verfolgt die Anzahl der Verweise auf ein bestimmtes Objekt.

Eine erste Idee könnte sein, die Circle-Klasse nach dem folgenden Schema zu implementieren:


Public Class Circle()
'Zähler der Klasseninstanzen
Public CountCircles As Integer
...
End Class

Dieser triviale Lösungsansatz ist durchaus realisierbar, aber aus programmiertechnischer Sicht alles andere als optimal. Er bereitet nämlich Probleme, die bei genauerer Analyse zutage treten:

gp  Verwaltet die Anwendung einige hundert Circle-Objekte, wäre das Feld CountCircles ebenso oft im Speicher vertreten, obwohl es immer denselben Wert hätte. Insbesondere bei Objekt-Arrays würden Speicherressourcen unnötig verschwendet.
gp  Der Zähler muss erhöht werden, sobald ein weiteres Objekt dieses Typs erzeugt wird – und das nicht nur im neuen Objekt, sondern auch in jedem bereits existierenden. Die Folge ist eine Leistungseinbuße, die umso größer wird, je mehr Objekte gleichen Typs verwaltet werden.

Den Zähler als Instanzvariable zu definieren, ist demnach kein guter Ansatz und bei den beschriebenen Nachteilen nicht akzeptabel. Aber wo liegt der grundlegende Fehler der Überlegung?

Die Antwort auf die Frage ist recht einfach: Instanzvariablen sind objektgebunden. Um den Objektzähler zu realisieren, brauchen wir aber ein Feld, losgelöst von jedem konkreten Objekt, das nur in einer festen Bindung zur Klasse Circle steht. Der Objektzähler wäre damit als eine gemeinsame Eigenschaft aller Objekte dieses Typs zu betrachten.

Probleme dieser Art, allen typgleichen Objekten klassen-, aber nicht objektgebundene Elemente zur Verfügung zu stellen, werden von Visual Basic 2005 durch den Modifizierer Shared gelöst. Bezogen auf die Forderung nach einem Objektzähler, würde ein erster Ansatz zur Problemlösung wie folgt aussehen:


Public Class Circle
' Klassenvariable
Public Shared CountCircles As Integer
...
End Class


Als Shared deklarierte Komponenten sind nicht an ein konkretes Objekt gebunden, sondern gehören dem Gültigkeitsbereich einer Klasse an. Klassenvariablen werden nur einmal für alle Objekte der spezifischen Klasse im Speicher vorgehalten.


Die standardmäßige Sichtbarkeit statischer Komponenten ist Public. Die Sichtbarkeit kann durch die Modifizierer Private, Protected und Friend an die Anforderungen angepasst werden.

An dieser Stelle eine Anmerkung. Shared bedeutet »gemeinsam« und beschreibt in der Übersetzung sehr verständlich die Charakteristik dieser Klassenelemente. Dennoch hat sich in der Objektorientierung der Begriff »statisch« etabliert, den ich auch in allen folgenden Ausführungen benutzen werde.


Galileo Computing

5.1.2 Zugriff auf statische Komponenten  downtop

Klassenmethoden und -felder sind unabhängig von den Objekten einer Klasse. Daher ist es unzulässig, sie auf eine Objektreferenz aufzurufen, und es führt sogar zu einem Kompilierfehler. Um eine Klassenvariable auszuwerten, reicht die Angabe des Typbezeichners. Ist in der Klasse Circle eine Klassenvariable CountCircles definiert, können Sie demnach mit


Dim x As Integer = Circle.CountCircles

auf den Inhalt zugreifen.

Auch Methoden können Shared sein. Für den Aufruf einer Klassenmethode gilt wie für ein statisches Feld, dass vor dem Methodenbezeichner der Klassenname angegeben werden muss. Klassenmethoden wurden schon häufig in den Beispielcodes dieses Buches benutzt: Es sind die Methoden WriteLine und ReadLine, die von der Klasse Console bereitgestellt werden.

Sind in einer Klasse sowohl statische als auch objektbezogene Eigenschaften und Methoden definiert, unterliegt der wechselseitige Zugriff der beiden Elementtypen den folgenden zwei Regeln:


Aus einer Instanzmethode heraus lassen sich Klassenvariablen manipulieren und Klassen-methoden aufrufen. Der umgekehrte Weg, nämlich aus einer statischen Methode heraus auf die Instanzeigenschaften und Instanzmethoden zuzugreifen, ist nicht möglich.


Galileo Computing

5.1.3 Statische Klassenvariable in der Klasse »Circle«  downtop

Für statische Felder gelten dieselben Regeln der Datenkapselung wie für Instanzvariablen. Eine Klassenvariable wie CountCircles sollte daher in derselben Weise gekapselt werden, um nicht mit dem objektorientierten Paradigma zu brechen. Dazu wird sie Private deklariert. Um den Zugriff von außerhalb sicherzustellen, implementieren wir in der Klasse Circle zusätzlich eine statische Eigenschaftsmethode. Damit eine Manipulation des Zählers von außerhalb unterbunden wird, muss die Eigenschaft durch Verzicht auf den Set-Accessor schreibgeschützt sein.


Public Class Circle
' --------- statische Felder --------------
Private Shared intCountCircles As Integer
' ---------- Klasseneigenschaften ----------
Public Shared ReadOnly Property CountCircles() As Integer
Get
Return intCountCircles
End Get
End Property
...
End Class

Nun enthält die Circle-Klasse den angestrebten Objektzähler, der beliebig abgefragt werden kann. Allerdings ist die Klassendefinition noch unvollständig, denn es fehlt die Programmlogik, um den Zähler mit jeder neuen Objektinstanz zu erhöhen. Dazu bieten sich die Konstruktoren an. Hierbei nutzen wir wieder die Konstruktorverkettung und erhöhen den Objektzähler nur im parameterlosen Konstruktor, der aus den beiden anderen Initialisierungsroutinen aufgerufen wird:


' ------------- Konstruktoren ---------------
Public Sub New()
intCountCircles += 1
End Sub
Public Sub New(ByVal radius As Double)
Me.New()
Me.Radius = radius
End Sub
Public Sub New(ByVal radius As Double, ByVal x As Integer, _
ByVal y As Integer)
Me.New(radius)
intXKoordinate = x
intYKoordinate = y
End Sub

Die Implementierung der Zählerverringerung ist nicht ganz so einfach und muss genauer überdacht werden. Bekanntlich zeichnet sich die Zerstörung einer Instanz durch die .NET-Laufzeitumgebung dadurch aus, dass der Garbage Collector seinen Dienst versieht und nicht vorhergesagt werden kann, wann er in Aktion tritt. Prinzipiell bieten sich zwei Lösungsansätze an:

1. Die Klassenvariable wird nur im Finalizer verringert. Allerdings muss dabei in Kauf genommen werden, dass die Angabe unter Umständen nicht die tatsächliche Anzahl der Circle-Objekte liefert.
       
2. Der Benutzer der Klasse wird gezwungen, die Methode Dispose aufzurufen, die für die Aktualisierung des Zählers sorgt. Vergisst der Client den Aufruf, ist der Zählerstand allerdings nicht korrekt und hinkt für eine unbestimmte Zeit den tatsächlichen Gegebenheiten hinterher.
       

Egal welche Lösung wir anstreben, eine Garantie, dass der Objektzähler immer den richtigen Stand zurückliefert, gibt es nicht. Die beste Lösung ist daher auch in diesem Fall die Formulierung einer Synthese aus beiden Lösungsansätzen: einerseits durch den expliziten Aufruf der Methode Dispose den Zählerstand zu aktualisieren, andererseits sich nicht auf die korrekte Implementierung im Client zu verlassen und als letzten Ausweg dem Garbage Collector diese Aufgabe zu überlassen.


Public Class Circle
...
Private bolReduced As Boolean
...
Protected Overrides Sub Finalize()
If Not bolReduced Then intCountCircles -= 1
End Sub
Public Sub Dispose() Implements IDisposable.Dispose
intCountCircles -= 1
bolReduced = True
End Sub
End Class

Um den internen Zähler intCountCircles nicht zweimal herabzusetzen und ihn in einem inkonsistenten Zustand zu hinterlassen, wird zur Verfolgung des Freigabezustands eines Objekts die private Variable bolReduced deklariert, die per Standard False initialisiert wird.

Bei einem ordnungsgemäßen Aufruf der Methode Dispose seitens des Benutzers wird der Objektzähler reduziert und das Flag bolReduced auf True gesetzt. Ruft der Speicherbereinigungsmechanismus die Finalize-Methode des Objekts auf, bleibt der Kreiszähler unverändert, weil die Bedingung zur Ausführung der Anweisung nicht erfüllt ist. Vergisst der Client jedoch den Aufruf von Dispose, behält das Flag seinen Initialisierungswert, und der Zerstörungsmechanismus wird für die Aktualisierung des Kreisobjektzählers sorgen.


Galileo Computing

5.1.4 Klassenspezifische Methoden  downtop

Neben den statischen Klasseneigenschaften können auch klassenbezogene Methoden definiert werden. Klassenmethoden sind unabhängig von einer bestimmten Klasseninstanz und werden ebenfalls mit dem Modifizierer Shared gekennzeichnet. Typischerweise werden statische Methoden da eingesetzt, wo allgemein gültige Operationen angeboten werden sollen. Ein typischer Vertreter des .NET Frameworks ist die Klasse Math. In dieser sind alle Methoden statisch.

Methoden gelten als überladen, wenn sie sich in der Parameterliste unterscheiden. An dieser Regel ändert auch der Modifizierer Shared nichts. Wenn Sie also versuchen, die Methode


Public Sub TestMethod()
...
End Sub

mit


Public Shared Sub TestMethod()
...
End Sub

zu überladen, wird die Kompilierung abgelehnt.

Weiter oben wurden zwei Regeln aufgestellt: Instanzmethoden können auf die statischen Mitglieder einer Klasse zugreifen, Klassenmethoden sind jedoch objektunabhängig und haben daher keinen Zugriff auf Instanzmember. Die Klassendefinition TestClass im folgenden Codebeispiel verdeutlicht diesen Sachverhalt. Die Instanzmethode EditVariable manipuliert sowohl die Instanzvariable LngVar als auch die Klassenvariable IntVar, die Klassenmethode ClassMethod hat nur den Zugriff auf die allen Objekten der Klasse gemeinsame Eigenschaft IntVar, nicht jedoch auf die objektspezifische LngVar.


Class TestClass
Public LngVar As Long
Public Shared IntVar As Integer
' Instanzmethode
Public Sub EditVariable()
LngVar = 24
IntVar = 4711
End Sub
' Klassenmethode
Public Shared Sub ClassMethod()
' ACHTUNG: unzulässiger Zugriff auf die Instanzvariable
LngVar = 100
End Sub
End Class


Galileo Computing

5.1.5 Statische Methoden in der Klasse »Circle«  downtop

Ehe wir die Klasse Circle um weitere Methoden ergänzen, wollen wir zunächst zwei Methoden zur Diskussion stellen, die bereits in Kapitel 4 entwickelt worden sind:


Public Function GetFlaeche(ByVal radius As Double) As Double
Return 3.14 * radius ^ 2
End Function
Public Function GetUmfang(ByVal radius As Double) As Double
Return 2 * 3.14 * radius
End Function

Beide Methoden haben allgemein gültigen Charakter, denn die erforderlichen Dateninformationen werden nicht aus dem Objekt bezogen, sondern aus dem jeweiligen Parameter. Damit sind GetFlaeche und GetUmfang genau genommen objektunabhängig und sollten durch Ergänzung des Modifizierers Shared zu statischen Methoden erklärt werden.


Public Shared Function GetFlaeche(ByVal radius As Double) As Double
Return 3.14 * radius ^ 2
End Function
Public Shared Function GetUmfang(ByVal radius As Double) As Double
Return 2 * 3.14 * radius
End Function

Die Instanzmethode mit Rückgabe einer Objektreferenz

Darüber hinaus soll die Klasse Circle um Methoden ergänzt werden, die in der Lage sind, zwei Kreisobjekte miteinander zu vergleichen. Das Ergebnis des Vergleichs sei die Rückgabe der Referenz auf das größere der beiden Circle-Objekte. Haben beide Kreise denselben Radius, soll der Rückgabewert die Referenz auf das im ersten Argument aufgeführte Objekt sein. Wir werden dazu sowohl Instanz- als auch Klassenmethoden bereitstellen.

Fangen wir mit der Instanzmethode an. Der Code dazu lautet wie folgt:


Public Function Bigger(ByVal kreis As Circle) As Circle
If Me.dblRadius >= kreis.dblRadius Then
Return Me
End If
Return kreis
End Function

Bigger prüft zuerst die Bedingung und benutzt dazu das Schlüsselwort Me. Beachten Sie, dass Me nur für Instanzvariablen und Instanzmethoden zur Verfügung steht und bei statischen Klassenmitgliedern weder Sinn macht noch erlaubt ist. Auf das Feld dblRadius der übergebenen Referenz kreis ist der Zugriff trotz der Private-Deklaration möglich, weil der Zugriff auf die privaten Member eines typgleichen Objekts gestattet ist.

Weniger empfehlenswert ist, über den Aufruf der beiden Eigenschaftsmethoden Radius die beiden Größen zu vergleichen, also:


If(Me.Radius >= kreis.Radius) Then ...

Die Folge wäre der Aufruf des Get-Accessors in der Eigenschaftsmethode. Das ist jedoch unnötig, weil das gekapselte Feld dblRadius in jedem Fall einen gültigen Wert enthält.

Angenommen, die beiden Objektreferenzen kreis1 und kreis2 sind vom Typ Circle, könnten wir Bigger auf das Objekt Kreis1 wie folgt aufrufen:


Dim newCircle As Circle = kreis1.Bigger(kreis2)

Die Referenz auf das größere der beiden Objekte wird der Objektvariablen newCircle zugewiesen oder – falls die beiden Kreise gleich groß sind – entsprechend der Methodenimplementierung die Referenz auf das Objekt, in dessen Kontext der Aufruf der Methode erfolgt.

Bigger ist nicht in der Lage, einen Benutzer über eine gegebenenfalls vorliegende radielle Gleichheit zu informieren. Das soll eine Überladung sicherstellen. Da wir dann allerdings auch zwei Ergebnisse an den Aufrufer zurückliefern, müssen wir die Parameterliste um einen ByRef-Parameter ergänzen.


Public Function Bigger(ByVal kreis As Circle, ByRef equal As Boolean) _
As Circle
equal = False
If Me.dblRadius = kreis.dblRadius Then
equal = True
End If
Return Me.Bigger(kreis)
End Function

Über equal wird dem Aufrufer bei ungleichen Radien False, ansonsten True zurückgeliefert. Die Prüfung der Radien beider Referenzen erfolgt über die vorher definierte einparametrige Bigger-Methode.

Wir wollen uns nun den Aufruf der zweiparametrigen Bigger-Methode an einem Codefragment ansehen.


Sub Main()
Dim equality As Boolean
Dim kreis1 As Circle = New Circle(32)
Dim kreis2 As Circle = New Circle(18)
Dim maxKreis As Circle = kreis1.Bigger(kreis2, equality)
If equality Then
Console.WriteLine("Beide Kreise sind gleich gross")
Else
Console.WriteLine("Beide Kreise haben verschiedene Radien")
End If
Console.Write("Radius (max) = {0}", maxKreis.Radius)
Console.ReadLine()
End Sub

Interessant ist die Auswertung des zweiten Parameters. In Main wird dazu die lokale Variable equality deklariert. Beim Methodenaufruf wird die Referenz auf diese Variable an Bigger übergeben. Bigger-Methode schreibt das Ergebnis der Prüfung in den Parameter equal. Der aufrufende Code ist in der Lage, dieses über seine lokale Variable equality auszuwerten.

Klassenmethoden mit Rückgabe einer Objektreferenz

Dasselbe Verhalten sollen jetzt auch noch zwei Klassenmethoden aufweisen. Weil der Aufruf einer Klassenmethode immer auf dem Klassennamen erfolgt, müssen die beiden zu vergleichenden Circle-Objekte an die Parameterliste übergeben werden.


Public Shared Function Bigger(ByVal kreis1 As Circle, _
ByVal kreis2 As Circle) As Circle
If kreis1.dblRadius >= kreis2.dblRadius Then
Return kreis1
End If
Return kreis2
End Function
Public Shared Function Bigger(ByVal kreis1 As Circle, _
ByVal kreis2 As Circle, ByRef equal As Boolean) As Circle
equal = False
If kreis1.dblRadius = kreis2.dblRadius Then
equal = True
End If
Return Circle.Bigger(kreis1, kreis2)
End Function

Größenvergleich mit booleschem Rückgabewert

Alle bisher implementierten Bigger-Methoden liefern dem Aufrufer jeweils die Referenz auf ein Circle-Objekt zurück. Wenn der Vergleich in einer Kontrollstruktur wie der bedingten Anweisung erfolgt, ist eher ein boolescher Rückgabewert von Interesse. Nehmen wir an, wir wollen nur wissen, ob der Radius einer Referenz größer ist als der Radius einer zweiten Referenz, und nehmen wir weiter an, dass die Methode, die einen Boolean liefert, IsBigger heißt und als Klassenmethode definiert ist. Dann könnte mit der Anweisung

If Circle.IsBigger(Kreis1, Kreis2) Then ...

der einfache Vergleich erfolgen.

Um diese Bedingungsprüfung durchführen zu können, wollen wir jetzt IsBigger implementieren. Wir legen dabei fest, dass der Methodenaufruf True zurückliefern soll, falls der Radius des Kreises des ersten Parameters größer oder gleich dem Kreis des zweiten Parameters ist. Das entspricht der Bedingung

kreis1.Radius >= kreis2.Radius

Mit dieser Vorgabe sieht die statische Methode wie folgt aus:


Public Shared Function IsBigger(ByVal kreis1 As Circle, _
ByVal kreis2 As Circle) As Boolean
If kreis1.Radius >= kreis2.Radius Then
Return True
End If
Return False
End Function

Selbstverständlich bestünde auch die Möglichkeit, zusätzlich eine Instanzmethode namens IsBigger anzubieten. Der Programmcode unterscheidet sich aber nur geringfügig von dem der hier gezeigten statischen Variante und trägt nicht weiter zum Verständnis bei. Daher wird an dieser Stelle darauf verzichtet.


Galileo Computing

5.1.6 Statische Klasseninitialisierer  downtop

Nach dem aktuellen Stand enthält die Klasse Circle mehrere Instanzfelder und eine Klassenvariable:


Private bolReduced As Boolean
Private intXKoordinate As Integer
Private intYKoordinate As Integer
Private dblRadius As Double
Private Shared intCountCircles As Integer

Klassen- und Instanzvariablen werden zu unterschiedlichen Zeitpunkten initialisiert. Dabei gilt die folgende Regel:


Instanzvariablen werden initialisiert, wenn bei der Instanziierung mit New ein Konstruktor aufgerufen wird. Klassenvariablen hingegen werden initialisiert, wenn die Klasse zum ersten Mal geladen wird. Das kann sein, wenn erstmalig auf ein statisches Klassenmitglied zugegriffen oder bevor das erste Objekt der Klasse erstellt wird, ohne dass vorher ein Zugriff auf ein statisches Element erfolgte.


Praktisch bedeutet das, dass uns bereits mit


Console.WriteLine(Circle.CountCircles)

ein Ergebnis angezeigt wird, ohne dass vorher ein Objekt dieses Typs erzeugt worden ist, während andererseits eine Instanzvariable grundsätzlich immer die Existenz eines konkreten Objekts voraussetzt.

Bei der Instanziierung einer Klasse wird ein Konstruktor aufgerufen. Auf Klassenbasis gibt es dazu ein Pendant, das als statischer Konstruktor oder statischer Initialisierer bezeichnet wird. Der statische Konstruktor ist eine an die Klasse gebundene Methode, die nur auf die statischen Mitglieder der Klasse Zugriff hat.

Der statische Konstruktor einer Klasse wird aufgerufen, bevor die erste Instanz erstellt wird oder der erste Zugriff auf ein statisches Klassenmitglied erfolgt. Die Definition eines statischen Konstruktors sieht folgendermaßen aus:


' Syntax des statischen Konstruktors
Shared Sub New()
...
End Sub

Beachten Sie, dass ein statischer Konstruktor, ähnlich wie der Finalizer, keinen Zugriffsmodifizierer akzeptiert. Da ein statischer Konstruktor automatisch aufgerufen wird und niemals direkt, macht eine Parameterliste keinen Sinn – die Klammern bleiben grundsätzlich leer.

Das folgende Codefragment zeigt einen statischen Initialisierer, der einer Klassenvariablen einen Wert zuweist.


Public Class ShowStatInit
' Klassenvariable
Private Shared statString As String
'Klasseninitialisierer
Shared Sub New()
statString = "Hallo Freunde."
End Sub
...
End Class

Selbstverständlich könnten wir denselben Effekt erzielen, wenn wir die statische Variable direkt mit


Public Shared str As String = "Visual Basic macht Spass."

initialisieren würden. Der statische Konstruktor bietet sich eher dazu an, komplexere Initialisierungen vorzunehmen. Dabei könnte es sich um das Auslesen von Dateien oder auch um die Initialisierung statischer Arrays handeln, wie das folgende Beispiel zeigt:


' --------------------------------------------------------------
' Beispiel: ...\Kapitel 5\StatischesArray
' --------------------------------------------------------------
Module Module1
Sub Main()
Dim i As Integer
For i = 0 To 100
Console.WriteLine("myArr({0}) = {1}", i, ClassA.myArr(i))
Next
Console.ReadLine()
End Sub
End Module
Class ClassA
' statisches Array
Public Shared myArr(100) As Integer
' statischer Konstruktor
Shared Sub New()
Dim rnd As Random = New Random()
Dim i As Integer
For i = 0 To 100
myArr(i) = rnd.Next(100)
Next
End Sub
End Class

Das Array myArr in der Klasse ClassA wird im statischen Konstruktor mit Werten zwischen 0 und 100 initialisiert, die nach dem Zufallsprinzip der Klasse Random gebildet werden. Zur Bestätigung erfolgt die Ausgabe des Array-Inhalts an der Konsole.

Aufrufreihenfolge der Konstruktoren

Statische Klasseninitialisierer und Konstruktoren sind sich in der Funktionsweise ähnlich. Während Klasseninitialisierer Klassendaten bereitstellen, versorgen Konstruktoren die objektspezifischen Felder mit Daten. Sobald Sie eine Objektvariable deklarieren, wird, soweit implementiert, der statische Konstruktor ausgeführt und erst danach der Konstruktor. Im Bedarfsfall dürfen Sie also im Konstruktor Code implementieren, der die vorhergehende Initialisierung der statischen Klassenmitglieder voraussetzt.


Galileo Computing

5.1.7 Zusammenfassung  toptop

gp  Statische Klassenelemente, gekennzeichnet durch den Modifizierer Shared, sind nicht an ein konkretes Objekt gebunden. Es gibt sowohl statische Felder als auch statische Eigenschaften und Methoden. Statische Klassenmitglieder werden über die Angabe des Klassennamens angesprochen.
gp  Ein statisches Feld existiert nur einmal im Speicher, unabhängig davon, wie viele Klasseninstanzen erzeugt werden.
gp  Klassenmethoden können weder Instanzvariablen manipulieren noch Instanzmethoden aufrufen. Andererseits haben Instanzmethoden die Möglichkeit, sowohl auf statische Felder zuzugreifen als auch statische Methoden auszuführen.
gp  Die Me-Referenz steht in statischen Methoden nicht zur Verfügung.
gp  Klassenvariablen werden initialisiert, sobald der erste Zugriff auf die Klasse erfolgt. Die Initialisierung der Klassenvariablen kann über den statischen Konstruktor erfolgen. Dieser wird automatisch aufgerufen, hat keinen Zugriffsmodifizierer und grundsätzlich eine leere Parameterliste.
gp  Wird erstmalig das Objekt eines Typs erzeugt, wird zuerst der statische Initialisierer aufgerufen und danach der Konstruktor zur Initialisierung der Objektdaten.
 <<   zurück
  
 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Buchtipps
Zum Katalog: Visual Basic 2012






 Visual Basic 2012


Zum Katalog: Schrödinger programmiert C++






 Schrödinger
 programmiert C++


Zum Katalog: IT-Handbuch für Fachinformatiker






 IT-Handbuch für
 Fachinformatiker


Zum Katalog: Professionell entwickeln mit Visual C# 2012






 Professionell
 entwickeln mit
 Visual C# 2012


Zum Katalog: Windows Presentation Foundation






 Windows Presentation
 Foundation


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo





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


[Rheinwerk Computing]

Galileo Press, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de