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

Inhaltsverzeichnis
1 Einführung
2 Grundlagen der Sprachsyntax
3 Klassendesign
4 Weitere Datentypen
5 Multithreading
6 Collections und LINQ
7 Eingabe und Ausgabe
8 Anwendungen: Struktur und Installation
9 Code erstellen und debuggen
10 Einige Basisklassen
11 Windows-Anwendungen erstellen
12 Die wichtigsten Steuerelemente
13 Tastatur- und Mausereignisse
14 MDI-Anwendungen
15 Grafiken mit GDI+
16 Drucken
17 Entwickeln von Steuerelementen
18 Programmiertechniken
19 WPF – Grundlagen
20 Layoutcontainer
21 WPF-Steuerelemente
22 Konzepte von WPF
23 Datenbankverbindung mit ADO.NET
24 Datenbankabfragen mit ADO.NET
25 DataAdapter
26 Offline mit DataSet
27 Datenbanken aktualisieren
28 Stark typisierte DataSets
A Anhang: Einige Übersichten
Stichwort

Buch bestellen
Ihre Meinung?

Spacer
<< zurück
Visual Basic 2008 von Andreas Kuehnel, Stephan Leibbrandt
Das umfassende Handbuch
Buch: Visual Basic 2008

Visual Basic 2008
3., aktualisierte und erweiterte Auflage, geb., mit DVD
1.323 S., 49,90 Euro
Rheinwerk Computing
ISBN 978-3-8362-1171-0
Pfeil 3 Klassendesign
Pfeil 3.1 Objektorientierung
Pfeil 3.1.1 Einführung
Pfeil 3.1.2 Vorteile
Pfeil 3.1.3 Klassenimplementierung in .NET
Pfeil 3.1.4 Klassen in Visual Basic
Pfeil 3.1.5 Projekttyp »Klassenbibliothek«
Pfeil 3.1.6 Bemerkung zu den Codefragmenten
Pfeil 3.1.7 Objekte durch New
Pfeil 3.1.8 Ausnahmen mit Throw auslösen
Pfeil 3.1.9 Datentypen
Pfeil 3.1.10 Sichtbarkeit der Klasse
Pfeil 3.1.11 Aufteilung der Definition mit Partial
Pfeil 3.1.12 Grafikbibliothek: Beispiel für Kapitel 3 und 4
Pfeil 3.2 Kapselung
Pfeil 3.2.1 Kombinationen
Pfeil 3.2.2 Private
Pfeil 3.2.3 Sichtbarkeitsmodifikatoren
Pfeil 3.2.4 Lokale Variablen
Pfeil 3.2.5 Softwareschutz
Pfeil 3.2.6 Grafikbibliothek: private Größe des Rechtecks
Pfeil 3.3 Verhalten (Methoden)
Pfeil 3.3.1 Prinzip
Pfeil 3.3.2 Verlassen der Methode
Pfeil 3.3.3 Parameter
Pfeil 3.3.4 Überladung (Overloads)
Pfeil 3.3.5 Rückgabewert
Pfeil 3.3.6 Reine Deklaration mit Partial
Pfeil 3.3.7 Grafikbibliothek: Zugriffsmethoden auf die Größe des Rechtecks
Pfeil 3.4 Bindung
Pfeil 3.4.1 Klassenbindung mit Shared
Pfeil 3.4.2 Klassenkonstruktoren
Pfeil 3.4.3 Externe Funktionen
Pfeil 3.4.4 Grafikbibliothek: Rechteckübergreifendes
Pfeil 3.5 Objektinitialisierung mit Konstruktoren
Pfeil 3.5.1 Objektkonstruktoren
Pfeil 3.5.2 Nichtöffentliche Konstrukturen
Pfeil 3.5.3 Grafikbibliothek: Initialisierung des Rechtecks
Pfeil 3.6 Zustände (Felder)
Pfeil 3.6.1 Deklaration und Initialisierung
Pfeil 3.6.2 Sichtbarkeit
Pfeil 3.6.3 Konstanten: ReadOnly und Const
Pfeil 3.6.4 With
Pfeil 3.6.5 Grafikbibliothek: Konstanten des Rechtecks
Pfeil 3.7 Eigenschaften
Pfeil 3.7.1 Kontrolle beim Aufrufer
Pfeil 3.7.2 Zugriffsmethoden
Pfeil 3.7.3 Getter und Setter: Property
Pfeil 3.7.4 Indexer
Pfeil 3.7.5 Standardeigenschaft: Default
Pfeil 3.7.6 Schreibschutz und Leseschutz: ReadOnly und WriteOnly
Pfeil 3.7.7 Sichtbarkeit
Pfeil 3.7.8 Klammern
Pfeil 3.7.9 Grafikbibliothek: Eigenschaften des Rechtecks
Pfeil 3.8 Innere Klassen
Pfeil 3.8.1 Beziehung zur äußeren Klasse
Pfeil 3.8.2 Sichtbarkeit
Pfeil 3.8.3 Grafikbibliothek: Position des Rechtecks
Pfeil 3.9 Dynamisches Verhalten: Delegate und Function
Pfeil 3.9.1 Funktionszeiger: Delegates
Pfeil 3.9.2 Automatisch generierter Code
Pfeil 3.9.3 Mehrere Aktionen gleichzeitig
Pfeil 3.9.4 Asynchrone Aufrufe
Pfeil 3.9.5 Funktionsobjekte: Function (λ-Ausdrücke)
Pfeil 3.9.6 Umwandlungen
Pfeil 3.9.7 Grafikbibliothek: Vergleich von Rechtecken
Pfeil 3.10 Ereignisse
Pfeil 3.10.1 Ereignis: Event und RaiseEvent
Pfeil 3.10.2 Statische Methodenbindung WithEvents und Handles
Pfeil 3.10.3 Dynamische Methodenbindung: AddHandler und RemoveHandler
Pfeil 3.10.4 Benutzerdefinierte Ereignisse: Custom Event
Pfeil 3.10.5 Umwandlungen
Pfeil 3.10.6 Grafikbibliothek: Größenänderungen von Rechtecken überwachen
Pfeil 3.11 Benutzerdefinierte Operatoren
Pfeil 3.11.1 Prinzip
Pfeil 3.11.2 Überladung
Pfeil 3.11.3 Vergleich
Pfeil 3.11.4 Typumwandlung mit CType: Widening und Narrowing
Pfeil 3.11.5 Wahrheitswerte: IsTrue und IsFalse
Pfeil 3.11.6 Grafikbibliothek: Addition und Umwandlung von Rechtecken
Pfeil 3.12 Alle Klassenelemente
Pfeil 3.12.1 Der Namensraum My
Pfeil 3.13 Vererbung
Pfeil 3.13.1 Klassenbeziehung durch Inherits
Pfeil 3.13.2 Sichtbarkeitsmodifikatoren
Pfeil 3.13.3 Zugriff auf Eltern mit MyBase
Pfeil 3.13.4 Modifikation: Shadows und Overloads (Overrides)
Pfeil 3.13.5 Abstrakte Klassen: MustInherit und MustOverride
Pfeil 3.13.6 Spezifische Catch-Blöcke
Pfeil 3.13.7 Eigene Ausnahmen
Pfeil 3.13.8 Arrays
Pfeil 3.13.9 Grafikbibliothek: neue Vielecke
Pfeil 3.14 Polymorphie
Pfeil 3.14.1 Virtuelle Methoden: Overridable und Overrides
Pfeil 3.14.2 Unterbrechen: Overloads, Shadows und Overrides
Pfeil 3.14.3 Unterbinden: NotInheritable, NotOverridable und MyClass
Pfeil 3.14.4 Konstruktoren
Pfeil 3.14.5 Equals
Pfeil 3.14.6 ToString
Pfeil 3.14.7 Grafikbibliothek: Objektsammlungen
Pfeil 3.15 Schnittstellen: Interface und Implements
Pfeil 3.15.1 Benennungen und Parameter
Pfeil 3.15.2 Schnittstellen und Vererbung
Pfeil 3.15.3 Schnittstellenvererbung
Pfeil 3.15.4 Schnittstelle oder abstrakte Klasse?
Pfeil 3.15.5 Grafikbibliothek: Flächen
Pfeil 3.16 Lebensende eines Objekts
Pfeil 3.16.1 Garbage Collector
Pfeil 3.16.2 Destruktoren
Pfeil 3.16.3 Dispose und Using


Rheinwerk Computing - Zum Seitenanfang

3.7 Eigenschaften Zur nächsten ÜberschriftZur vorigen Überschrift

»Die Ungeduld ist ein schnelles Pferd, aber ein schlechter Reiter.« (Serbisches Sprichwort)

Der direkte Zugriff auf Objektzustände mag schnell sein, aber er kann leicht dazu führen, dass ein Objekt »ungültig« wird. So ist es zum Beispiel unsinnig, einem Rechteck eine negative Länge zu geben. Es kann auch passieren, dass durch das Ändern eines Objektzustandes Aktionen erforderlich werden. So sollte vor Umleitung des Standardausgabekanals geprüft werden, ob dieser Kanal benutzbar ist, um zu vermeiden, dass Ausgaben im Nirwana landen. Daher beschäftigen wir uns nun mit einem kontrollierten Zugriff auf Objektzustände.


Rheinwerk Computing - Zum Seitenanfang

3.7.1 Kontrolle beim Aufrufer Zur nächsten ÜberschriftZur vorigen Überschrift

Die einfachste Art, »falsche« Werte für Objektzustände zu vermeiden, ist es, vor jeder Zuweisung die Werte auf ihre Richtigkeit zu überprüfen. Dies hat ein paar Nachteile:

  • Bei jeder Zuweisung muss vorher die Richtigkeit kontrolliert werden.
  • Wird eine Kontrolle vergessen, kann das Objekt »ungültig« werden.
  • Ändern sich die Bedingungen der Kontrolle, müssen alle Zuweisungen angepasst werden.

Diese Nachteile machen es fast unmöglich, eine Klasse an andere weiterzugeben, da es in der Praxis fast sicher ist, dass bei so vielen Stellen irgendwo etwas schiefgeht. Wir werden daher diese Möglichkeit hier nicht weiter verfolgen.


Rheinwerk Computing - Zum Seitenanfang

3.7.2 Zugriffsmethoden Zur nächsten ÜberschriftZur vorigen Überschrift

Mit den bisherigen Mitteln können wir den Zugang zu Objekteigenschaften mittels Methoden kontrollieren, wenn wir die Objektzustände als privat kennzeichnen, um Änderungen von außen zu unterbinden. Das folgende Codefragment zeigt ein Quadrat, dessen Länge nicht null oder negativ werden kann. Dadurch, dass auch der Konstruktorparameter die Zugriffsmethode durchläuft, ist es auch nicht möglich, ein »ungültiges« Quadrat zu erzeugen. Der Grund für die Namen der Zugriffsmethoden wird im nächsten Abschnitt klar.


'...\Klassendesign\Eigenschaften\Zugriffsmethoden.vb

Option Explicit On 
Namespace Klassendesign

  Class QuadratZugriff 
    Private Länge As Double

    Sub set_Länge(ByVal value As Double) 
      If value <= 0 Then Throw New ArgumentException() 
      Länge = value 
    End Sub

    Function get_Länge() As Double 
      Return Länge 
    End Function

    Sub New(ByVal value As Double) 
      set_Länge(value) 
    End Sub 
  End Class

  Module Zugriffsmethoden 
    Sub Test() 
      Dim q As QuadratZugriff = New QuadratZugriff(8) 
      Try 
        q.set_Länge(-4) 
      Catch ex As Exception 
        Console.WriteLine("Negative Länge.") 
      End Try 
      Console.WriteLine("Quadrat {0}x{0}", q.get_Länge()) 
      Console.ReadLine() 
    End Sub 
  End Module 
End Namespace

Die Ausgabe zeigt, dass die Zuweisung der negativen Länge zurückgewiesen wurde:

Negative Länge. 
Quadrat 8x8

Rheinwerk Computing - Zum Seitenanfang

3.7.3 Getter und Setter: Property Zur nächsten ÜberschriftZur vorigen Überschrift

Das vorherige Beispiel kann mithilfe von Eigenschaftsmethoden konsistenter formuliert werden. Die Syntax solcher Zugriffe lautet (optionale Teile stehen in eckigen Klammern und kursive Teile müssen Sie Ihren Bedürfnissen anpassen):


[<Modifikatoren>] Property Name ([<Indizes>]) As Typ [Effekt] 
  [<Sichtbarkeit>] Get 
    [<Anweisungen>] 
  End Get 
  [<Sichtbarkeit>] Set(Wert As Typ) 
    [<Anweisungen>] 
  End Set 
End Property

Ob zuerst Get oder Set definiert wird, spielt keine Rolle. Die Indizes können beliebige Typen haben. Der Typ der Eigenschaft und des Wert-Parameters des Set-Teils müssen übereinstimmen. Tabelle 3.9 zeigt die erlaubten Modifikatoren und Tabelle 3.10 die Effekte.


Tabelle 3.9 Modifikatoren eines Ereignisses

Art Beschreibung

Sichtbarkeit

Grad der Öffentlichkeit (siehe Abschnitt 3.2, »Kapselung«)

Bindung

Objekt- oder klassenbezogen (siehe Abschnitt 3.4, »Bindung«)

Redefinition

Art des Ersatzes oder Zwangs zu einer Definition (siehe Abschnitt 3.13, »Vererbung« und Abschnitt 3.3.4, »Überladung (Overloads)«; Letzteres nur für Indizes)

Standard

Standardeigenschaften (siehe Abschnitt 3.7.5, »Standardeigenschaft: Default«)



Tabelle 3.10 Effekt eines Ereignisses

Art Beschreibung

Implementation

Erfüllung einer Schnittstelle (siehe Abschnitt 3.15, »Schnittstellen: Interface und Implements«)


Die Benutzung einer Eigenschaft ist sehr einfach:

  • Eigenschaft = wert ruft automatisch die Set-Methode auf und übergibt wert.
  • Eigenschaft allein ruft automatisch die Get-Methode auf.

Damit ist es nach außen völlig transparent, ob man ein Feld oder eine Eigenschaft verwendet. Dies erleichtert auch enorm die Änderung eines Feldes in eine Eigenschaft: Nur die Deklaration muss angepasst werden; bei der Benutzung ändert sich rein gar nichts.

Das folgende Codefragment hat die gleiche Semantik (Bedeutung) wie das Beispiel des vorigen Abschnitts. Der Zugriff auf die Eigenschaft in der Methode Test erfolgt, als wäre es ein Objektfeld.


'...\Klassendesign\Eigenschaften\GetUndSet.vb

Option Explicit On 
Namespace Klassendesign

  Class QuadratGetSet 
    Private len As Double

    Property Länge() As Double 
      Get 
        Return len 
      End Get 
      Set(ByVal val As Double) 
        If val <= 0 Then Throw New ArgumentException() 
        len = val 
      End Set 
    End Property

    Sub New(ByVal value As Double) 
      Länge = value 
    End Sub 
  End Class

  Module Eigenschaftsmethoden 
    Sub Test() 
      Dim q As QuadratGetSet = New QuadratGetSet(7) 
      Try 
        q.Länge = –3 
      Catch ex As Exception 
        Console.WriteLine("Negative Länge. ") 
      End Try 
      Console.WriteLine("Quadrat {0}x{0}", q.Länge) 
      Console.ReadLine() 
    End Sub 
  End Module 
End Namespace

Im vorigen Abschnitt wurden als Namen der Zugriffsmethoden set_Länge und get_Länge gewählt. Wenn Sie nun versuchen, in der nun definierten Klasse mit der Eigenschaft Länge eine dieser Methoden zu definieren, bekommen Sie vom Compiler eine Fehlermeldung, die besagt, dass diese Methoden implizit bereits definiert sind und ein Namenskonflikt vorliegt. Trotzdem ist es Ihnen nicht gestattet, eine dieser Methoden direkt selbst aufzurufen. Dies bleibt der Eigenschaft vorbehalten. Wenn Sie dennoch darauf bestehen, die Methoden selbst aufzurufen, bleibt Ihnen nur der Weg über eine dynamische Typanalyse, Reflection genannt. Das folgende Codefragment spricht die Get-Methode an und ist nur als Hinweis gedacht, dass manchmal mehr möglich ist, als es auf den ersten Blick scheint.

Dim q As QuadratGetSet = New QuadratGetSet(7) 
Dim t As Type = GetType(QuadratGetSet) 
Dim m As System.Reflection.MethodInfo = t.GetMethod("get_Länge") 
Dim len As Double = m.Invoke(q, New Object() {}) 
Console.WriteLine("len {0}", len)

Hinweis
Automatisch implementierte Eigenschaften wie in C# gibt es in Visual Basic nicht.



Rheinwerk Computing - Zum Seitenanfang

3.7.4 Indexer Zur nächsten ÜberschriftZur vorigen Überschrift

Eine Eigenschaft kann über Parameter zusätzlich qualifiziert werden. Die Anzahl und Typen der Parameter sind beliebig, aber alle müssen mit ByVal als Wert übergeben werden. Unter gleichem Namen dürfen Eigenschaften existieren, die über verschiedene Arten (und/oder Anzahl) von Parametern angesprochen werden. Dies ist analog zur Methodenüberladung (siehe Abschnitt 3.3.4, »Überladung (Overloads)«). Da wie dort der Rückgabetyp nicht zur Signatur gehört (siehe Abschnitt 3.3.1, »Prinzip«), dürfen gleich benannte Eigenschaften mit verschiedenen Parameterlisten unterschiedliche Typen haben. Programmtechnisch gesehen, haben sie nichts miteinander zu tun; der gleiche Name macht es Ihnen leichter, den Quelltext zu lesen.

Das nächste Codefragment stellt für platonische Körper deren Eckenzahl zur Verfügung. Es gibt nur fünf solcher Körper, die durch identische regelmäßige Vielecke begrenzt sind. Dadurch ist es nicht nötig, ein Objekt zu generieren, und alle Klassenelemente sind mit Shared an die Klasse gebunden. Auf einen Körper kann sowohl lesend als auch schreibend entweder mit einem numerischen Integer-Index oder mit dem String-Namen des Körpers zugegriffen werden. Beim Aufruf mit einem Namen wandelt Array.IndexOf diesen in einen Index um und verwendet dann die mit einer ganzen Zahl indizierte Ecken-Eigenschaft, sodass alle Zugriffe über diese laufen. Dort wäre der Platz für Prüfroutinen, die hier weggelassen worden sind, um das Beispiel einfach zu halten.


'...\Klassendesign\Eigenschaften\Indexer.vb

Option Explicit On 
Namespace Klassendesign 
  Class Platonisch 
    Friend Shared ReadOnly Fig() As String = { _ 
      "Tetraeder", "Würfel", "Oktaeder", "Dodekaeder", "Ikosaeder"} 
    Private Shared eckenzahl(4) As Byte

    Shared Property Ecken(ByVal index As Integer) As Byte 
      Get 
        Return eckenzahl(index) 
      End Get 
      Set(ByVal val As Byte) 
        eckenzahl(index) = val 
      End Set 
    End Property

    Shared Property Ecken(ByVal name As String) As Byte 
      Get 
        Return Ecken(Array.IndexOf(Fig, name)) 
      End Get 
      Set(ByVal val As Byte) 
        Ecken(Array.IndexOf(Fig, name)) = val 
      End Set 
    End Property

  End Class 
  ... 
End Namespace

Die Verwendung der überladenen Eigenschaft kann über den Namen oder den numerischen Index erfolgen. Da die Eigenschaft an die Klasse gebunden ist, erfolgt der Zugriff über den Klassennamen. Wie die dritte Zuweisung zeigt, sind auch Operatoren erlaubt, die implizit den Zuweisungsoperator verwenden.


'...\Klassendesign\Eigenschaften\Indexer.vb

Option Explicit On 
Namespace Klassendesign 
  ... 
  Module Indexer 
    Sub Test() 
      Platonisch.Ecken("Tetraeder")  = 4 
      Platonisch.Ecken(1)            = 7   'Würfel 
      Platonisch.Ecken("Würfel")    += 1 
      Platonisch.Ecken("Oktaeder")   = 6 
      Platonisch.Ecken("Dodekaeder") = 20 
      Platonisch.Ecken("Ikosaeder")  = 12

      Try 
        Platonisch.Ecken("Unbekannt") = 10 
      Catch ex As Exception 
        Console.WriteLine("Fehler: " & ex.Message) 
      End Try

      Console.WriteLine("{0} hat {1} Ecken", "Würfel", _ 
                        Platonisch.Ecken("Würfel"))

      Console.WriteLine("{0} hat {1} Ecken", "Dodekaeder", _ 
                        Platonisch.Ecken(3)) 
      Console.ReadLine() 
    End Sub 
  End Module 
End Namespace

Die Ausgabe zeigt, dass der »falsche« Index erfasst wurde und dass der namentliche und indizierte Zugriff gleichwertig sind:

Fehler: Index was outside the bounds of the array. 
Würfel hat 8 Ecken 
Dodekaeder hat 20 Ecken

Implizite Umwandlung

Durch implizite Umwandlungen kann es Ihnen passieren, dass eine Eigenschaft angesprochen wird, auch wenn der Typ nicht passt. Im nächsten Codefragment werden die Zahlen von der Eigenschaft akzeptiert, obwohl eine Zeichenkette erwartet wird:


'...\Klassendesign\Eigenschaften\Implizit.vb

Option Explicit On 
Namespace Klassendesign 
  Class Implizit 
    Friend Shared ReadOnly m() As String = {8.35}

    Shared Property Zugriff(ByVal name As String) As String 
      Get 
        Return m(Array.IndexOf(m, name)) 
      End Get 
      Set(ByVal val As String) 
        m(Array.IndexOf(m, name)) = val 
      End Set 
    End Property

  End Class 
  Module Typumwandlung 
    Sub Test() 
      Implizit.Zugriff(8.35) = –8.35 
      Console.WriteLine(Implizit.Zugriff(-8.35)) 
      Console.ReadLine() 
    End Sub 
  End Module 
End Namespace

Hinweis
Beim Aufruf einer indizierten Eigenschaft werden, wie bei Methoden, auch benutzerdefinierte implizite Umwandlungen berücksichtigt.



Rheinwerk Computing - Zum Seitenanfang

3.7.5 Standardeigenschaft: Default Zur nächsten ÜberschriftZur vorigen Überschrift

Um den Zugriff auf parametrisierte Eigenschaften zu vereinfachen, kann je eine Eigenschaft pro Klasse mit Default als Standardeigenschaft gekennzeichnet werden. Bei einer solchen Eigenschaft muss der Eigenschaftsname beim Zugriff nicht angegeben werden. Bei einparametrigen Eigenschaften mit einer Zeichenkette als Parameter kann die Eingabe durch die Verwendung des Ausrufezeichens noch weiter verkürzt werden: Dann fallen selbst Klammern und Anführungszeichen weg.

Das nächste Codefragment hat eine ähnliche Bedeutung (Semantik) wie das erste Beispiel des vorigen Abschnitts. Die Eigenschaft ist nun objektgebunden und als Standardeigenschaft gekennzeichnet. Ebenso wie bisher ist die Eigenschaft überladen (Integer- bzw. String-Parameter).


'...\Klassendesign\Eigenschaften\Default.vb

Option Explicit On 
Namespace Klassendesign 
  Class Eder 
    Friend Fig() As String = {} 
    Private Shared zahl(-1) As Byte

    Default Property Flächen(ByVal index As Integer) As Byte 
      Get 
        Return zahl(index) 
      End Get 
      Set(ByVal val As Byte) 
        zahl(index) = val 
      End Set 
    End Property

    Default Property Flächen(ByVal name As String) As Byte 
      Get 
        Return Flächen(Array.IndexOf(Fig, name)) 
      End Get 
      Set(ByVal val As Byte) 
        Dim index As Integer = Array.IndexOf(Fig, name) 
        If index < 0 Then 
          index = Fig.Length 
          ReDim Preserve Fig(index) 
          ReDim Preserve zahl(index) 
          Fig(index) = name 
        End If 
        Flächen(index) = val 
      End Set 
    End Property

  End Class 
  ... 
End Namespace

Bei der Verwendung kann sowohl beim Schreiben als auch beim Lesen der Eigenschaftsname Fläche wegfallen. Der letzte Zugriff zeigt, dass mit einem Ausrufezeichen die Formulierung noch straffer wird:


'...\Klassendesign\Eigenschaften\Default.vb

Option Explicit On 
Namespace Klassendesign 
  ... 
  Module Standard 
    Sub Test() 
      Dim platonisch As Eder = New Eder() 
      platonisch("Ikosaeder") = 20 
      platonisch("Tetraeder") = 4 
      platonisch("Würfel") = 6 
      platonisch("Oktaeder") = 8 
      platonisch("Dodekaeder") = 12

      Console.WriteLine("{0} hat {1} Flächen", _ 
        "Würfel", platonisch("Würfel"))

      Console.WriteLine("{0} hat {1} Flächen", _ 
        "Oktaeder", platonisch(3))

      Console.WriteLine("{0} hat {1} Flächen", _ 
        "Tetraeder", platonisch!Tetraeder) 
      Console.ReadLine() 
    End Sub 
  End Module 
End Namespace

Die Ausgabe bestätigt den korrekten Zugriff:

Würfel hat 6 Flächen 
Oktaeder hat 8 Flächen 
Tetraeder hat 4 Flächen

Rheinwerk Computing - Zum Seitenanfang

3.7.6 Schreibschutz und Leseschutz: ReadOnly und WriteOnly Zur nächsten ÜberschriftZur vorigen Überschrift

Alle bisherigen Eigenschaften konnten gelesen und geschrieben werden. Es gibt Fälle, in denen dies unerwünscht ist. Zum Beispiel besteht ein fester Zusammenhang zwischen der Seitenlänge eines Quadrats und seiner Fläche. Da sich die Größe des Quadrats ändern kann, die Formel für die Flächenberechnung aber konstant bleibt, bietet es sich an, die Fläche mit einer Methode zu ermitteln. Eine Alternative ist die Verwendung einer mit ReadOnly schreibgeschützten Eigenschaft. Ob man eine Methode oder eine ReadOnly-Eigenschaft wählt, ist Geschmackssache.

Analog kann sich die Gelegenheit ergeben, dass ein Wert gespeichert werden soll, aber danach nicht mehr von außen zugänglich sein soll. Ein Beispiel ist die Speicherung eines Kennworts. Es reicht, wenn dieses intern zu Vergleichszwecken verwendet wird. Es sollte nicht lesbar sein.

Das folgende Codefragment definiert ein Quadrat, dessen Länge gesetzt, aber nicht mehr ausgelesen werden kann:


'...\Klassendesign\Eigenschaften\Schutz.vb

Option Explicit On 
Namespace Klassendesign 
  Class QuadratischeFläche 
    Private len As Double

    WriteOnly Property Länge() As Double 
      Set(ByVal val As Double) 
        If val <= 0 Then Throw New ArgumentException() 
        len = val 
      End Set 
    End Property

    ReadOnly Property Fläche() As Double 
      Get 
        Return len * len 
      End Get 
    End Property

    Sub New(ByVal value As Double) 
      Länge = value 
    End Sub 
  End Class 
  ... 
End Namespace

Eine geschützte Eigenschaft (ReadOnly oder WriteOnly) wird genauso benutzt wie jede andere Eigenschaft. Der Schutz betrifft die Möglichkeit, das Schreiben oder Lesen ganz zu unterbinden. Dies hat keinen Einfluss darauf, wie eine erlaubte Aktion durchgeführt wird.


'...\Klassendesign\Eigenschaften\Schutz.vb

Option Explicit On 
Namespace Klassendesign 
  ... 
  Module Schutz 
    Sub Test() 
      Dim q As QuadratischeFläche = New QuadratischeFläche(7) 
      q.Länge = 4 
      Try 
        q.Länge = –3 
      Catch ex As Exception 
        Console.WriteLine("Negative Länge. ") 
      End Try 
      Console.WriteLine("Quadratfläche {0}", q.Fläche) 
      Console.ReadLine() 
    End Sub 
  End Module 
End Namespace

Die Ausgabe bietet keine Überraschung:

Negative Länge. 
Quadratfläche 16

Rheinwerk Computing - Zum Seitenanfang

3.7.7 Sichtbarkeit Zur nächsten ÜberschriftZur vorigen Überschrift

Die Sichtbarkeit der Get- und der Set-Methode können Sie getrennt steuern. Das folgende Codefragment zeigt eine mittels einer privaten Set-Methode schreibgeschützte Eigenschaft, die jeden Lesezugriff protokolliert. Eine Konstante könnte den Aspekt des Schreibgeschützten erfüllen, nicht aber die Protokollierung. Seiteneffekte mit permanenter Wirkung, wie zum Beispiel die Änderung von Variablen, sollten in Leseroutinen vermieden werden, da diese sich konzeptuell wie eine einfache Variable verhalten sollten.


'...\Klassendesign\Eigenschaften\Sichtbarkeit.vb

Option Explicit On 
Namespace Klassendesign 
  Class Erlaubnis 
    Private erlaubt As Boolean 
    Friend ReadOnly log As String

    Property Darf() As Boolean 
      Get 
        Console.WriteLine("Zugriff {0}", log) 
        Return erlaubt 
      End Get 
 
      Private Set(ByVal val As Boolean) 
        erlaubt = val 
      End Set 
    End Property

    Sub New(ByVal user As String) 
      Me.log = user : erlaubt = user = "Admin" 
    End Sub 
  End Class

  Module Sichtbarkeit 
    Sub Test() 
      Dim admin As Erlaubnis = New Erlaubnis("Admin") 
      Dim user As Erlaubnis = New Erlaubnis("Nutzer") 
      Console.WriteLine("{0} darf {1}",admin.log,admin.Darf) 
      Console.WriteLine("{0} darf {1}", user.log, user.Darf) 
      Console.ReadLine() 
    End Sub 
  End Module 
End Namespace

Die Ausgabe zeigt die Protokollierung der Zugriffe:

Zugriff Admin 
Admin darf True 
Zugriff Nutzer 
Nutzer darf False

Rheinwerk Computing - Zum Seitenanfang

3.7.8 Klammern Zur nächsten ÜberschriftZur vorigen Überschrift

In seltenen, zweideutigen Situationen wird ein geklammerter Ausdruck vorrangig als parametrisierte Eigenschaft interpretiert und nicht zum Beispiel als Arrayzugriff. Das folgende Codefragment hat im Else-Zweig der Eigenschaft den Zugriff Q(i-1). Er wird als Aufruf der Eigenschaft interpretiert (rekursiver Aufruf der Eigenschaft) und nicht als Indizierung des zurückgegebenen Arrays (As Int32()). Die Eigenschaft berechnet eine Liste der ersten i Quadrate (das ginge auch einfacher mit einer Schleife …).


'...\Klassendesign\Eigenschaften\Klammern.vb

Option Explicit On 
Namespace Klassendesign

  Class Mathe 
    Shared ReadOnly Property Q(ByVal i As Int32) As Int32() 
      Get 
        If i = 0 Then Q = New Int32() {} _ 
        Else Q = Q(i-1).Concat(New Int32() {i*i}).ToArray() 
      End Get 
    End Property 
  End Class

  Module Klammern 
    Sub Test() 
      Randomize() 
      For Each data As Integer In Mathe.Q(7) 
        Console.Write(data & " ") 
      Next 
      Console.WriteLine() 
      Console.ReadLine() 
    End Sub 
  End Module 
End Namespace

Rheinwerk Computing - Zum Seitenanfang

3.7.9 Grafikbibliothek: Eigenschaften des Rechtecks topZur vorigen Überschrift

In diesem Abschnitt erweitern wir die in Abschnitt 3.1.12, »Grafikbibliothek: Beispiel für Kapitel 3 und 4«, eingeführte und zuletzt in Abschnitt 3.6.5, »Grafikbibliothek: Konstanten des Rechtecks«, erweiterte Grafikanwendung. Die Länge wird als Eigenschaft zugänglich gemacht, wobei der Aufruf Größe() in Set negative Längen abfängt (siehe Abschnitt 3.3.7, »Grafikbibliothek: Zugriffsmethoden auf die Größe des Rechtecks«). Die über einen Namen spezifizierten Abmessungen sind nur-lesbar.


'...\Klassendesign\Graphik\Eigenschaften.vb

Option Explicit On 
Namespace Klassendesign 
  Partial Public Class Rechteck

    Property Länge() As Double 
      Get 
        Return a 
      End Get 
      Set(ByVal a As Double) 
        Größe(a, b) 
      End Set 
    End Property

    Default ReadOnly Property Abmessung(ByVal was As String) As Double 
      Get 
        Select Case was 
          Case "Länge" : Return a 
          Case "Breite" : Return b 
          Case Else 
            Throw New ArgumentException("Weder Länge noch Breite.") 
        End Select 
      End Get 
    End Property

  End Class 
End Namespace

Zuerst wird ein neues Rechteck erzeugt und dessen Größe ausgegeben. Dann wird die Länge über die gleichnamige Eigenschaft geändert und erneut die Größe protokolliert. Die Zuweisung einer negativen Länge erzeugt eine Ausnahme und wird in einen Try-Catch-Block eingeschlossen. Die vorletzte Ausgabe dient zur Prüfung, dass die Länge daraufhin tatsächlich unverändert ist. Dieselbe Länge wird dann erneut über die Standardeigenschaft ausgelesen.


'...\Klassendesign\Zeichner\Eigenschaften.vb

Option Explicit On 
Namespace Klassendesign 
  Partial Class Zeichner 
    Sub Eigenschaften() 
      Dim rechteck As New Rechteck(7, 8) : rechteck.Größe()

      rechteck.Länge = 4 : rechteck.Größe()

      Try 
        rechteck.Länge = –3 
      Catch ex As Exception 
        Console.WriteLine("Ausnahme: " & ex.Message) 
      End Try

      Console.WriteLine("Länge des Rechtecks: {0}", rechteck.Länge) 
      Console.WriteLine("Länge des Rechtecks: {0}", rechteck("Länge"))

    End Sub 
  End Class 
End Namespace

Zur Kontrolle sehen Sie hier die Ausgabe der Methode Eigenschaften():

Dimension des Rechtecks: 7x8 
Dimension des Rechtecks: 4x8 
Ausnahme: Negative Länge! 
Länge des Rechtecks: 4 
Länge des Rechtecks: 4

Die nächste Erweiterung erfolgt in Abschnitt 3.8.3, »Grafikbibliothek: Position des Rechtecks«.



Ihr Kommentar

Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen. >> Zum Feedback-Formular
<< zurück
  Zum Katalog
Zum Katalog: Visual Basic 2008
Visual Basic 2008
Jetzt bestellen


 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Buchempfehlungen
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 2009
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]

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