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

Jetzt 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.11 Benutzerdefinierte Operatoren Zur nächsten ÜberschriftZur vorigen Überschrift

Die Gründe dafür, selbst Operatoren für Datentypen zu definieren, lassen sich in zwei Gruppen unterteilen:

  • Bequemlichkeit: Der Quelltext kann kürzer formuliert werden.
  • Implizite Nutzung: Die Operatoren CType, IsTrue und IsFalse werden gegebenenfalls von Code aufgerufen, der vom Compiler automatisch erstellt wird.

Hinweis
Ein einmal definierter Operator kann nicht mehr geändert werden (Polymorphie für klassengebundene Methoden gibt es nicht in Visual Basic, siehe Abschnitt 3.14, »Polymorphie«).



Rheinwerk Computing - Zum Seitenanfang

3.11.1 Prinzip Zur nächsten ÜberschriftZur vorigen Überschrift

Tabelle 3.19 teilt die benutzerdefinierbaren Operatoren in fünf Gruppen ein.


Tabelle 3.19 Operatoren und ihre Anwendungsbereiche

Anwendungsbereich Operator

Arithmetik

+ – * / \ ^ Mod << >> And Or Xor (+- auch unär)

Vergleich

= <> > < >= <= Like

Logik

Not IsTrue IsFalse And Or Xor

Zeichenketten

&

Typumwandlung

CType


Zwei Arten von Operatoren sind nicht neu definierbar, können aber zum Teil auf benutzerdefinierte Operatoren zurückgreifen:

  • = selbst kann nicht neu definiert werden, aber alle zusammengesetzten Zuweisungsoperatoren nutzen passende benutzerdefinierte Operatoren für den Nicht-Zuweisungsteil des Operators.
  • AndAlso und OrElse selbst können nicht neu definiert werden, aber sie nutzen passende benutzerdefinierte Operatoren von And, Or, IsTrue und IsFalse.

Alle Parameter der benutzerdefinierten Operatoren werden mit ByVal als Wert übergeben. Die Syntax der Definition lautet (optionale Teile stehen in eckigen Klammern und kursive Teile müssen Sie Ihren Bedürfnissen anpassen):


Public Shared [<Modifikatoren>] Operator oper(<Parameter>) As Typ 
  [<Anweisungen>] 
End Operator


Hinweis
Mindestens einer der Operanden (bei Typumwandlungen: oder der Rückgabewert) muss vom Typ der definierenden Klasse sein.


Tabelle 3.20 zeigt die erlaubten Modifikatoren.


Tabelle 3.20 Modifikatoren eines Operators

Art Beschreibung

Redefinition

Art des Ersatzes oder Zwangs zu einer Definition (siehe Abschnitt 3.13, »Vererbung« und Abschnitt 3.3.4, »Überladung (Overloads)«)

Typumwandlung

Explizit oder implizit (siehe Abschnitt 3.11.4, »Typumwandlung mit CType: Widening und Narrowing«)


Für jeden benutzerdefinierten Operator fügt der Compiler automatisch eine öffentliche Methode hinzu, deren Name mit op_ beginnt. In Tabelle 3.21 ist dieser Namensteil weggelassen. Die Methodennamen für die Operatoren Not, And, Or und Xor sind gleich für logische und bitweise Operationen. Beim Zusammenspiel mit anderen Programmiersprachen werden bei konkurrierenden logischen und bitweisen Operatoren die logischen ignoriert. Analog wird bei Bitschiebeoperatoren gegebenenfalls nur die vorzeichenbehaftete Version berücksichtigt. Anderen Programmiersprachen wird die ganzzahlige Division \ als normale Division / mit korrekter Bedeutung zur Verfügung gestellt. Statt des Operators kann auch die korrespondierende Methode verwendet werden.


Hinweis
Die alleinige Definition einer Operatormethode reicht nicht aus, um einen Operator verwenden zu können.



Tabelle 3.21 Operatoren und korrespondierende Methoden

Methode op_ Methode op_ Methode op_

+

Addition

<<

LeftShift

=

Equality

+

UnaryPlus

>>

RightShift

<>

Inequality

-

Subtraction

And

BitwiseAnd

<

LessThan

-

UnaryNegation

Or

BitwiseOr

>

GreaterThan

*

Multiply

Xor

ExclusiveOr

<=

LessThanOrEqual

/

Division

Not

OnesComplement

>=

GreaterThanOrEqual

^

Exponent

\

IntegerDivision

Like

Like

Mod

Modulus

&

Concatenate

Widening CType

Implicit

IsTrue

True

Narrowing CType

Explicit

IsFalse

False



Hinweis
Sie müssen selbst darauf achten, dass ein Operator und der Typ seines Rückgabewerts eine sinnvolle Kombination ergeben. Bei IsTrue und IsFalse ist der Typ der Rückgabe zwingend Boolean.


Schauen wir uns ein Beispiel an. Das folgende Codefragment definiert eine Matrix mit Fließkommazahlen, die mit dem Stringverkettungsoperator & komfortabel ausgegeben werden kann. Die Methode Append() übernimmt die Formatierung. Die Variable ein bestimmt die nötige Einrückung folgender Zeilen, indem sie die bisherige Ausgabe str mithilfe regulärer Ausdrücke durch Leerzeichen ersetzt. PadLeft() sorgt dafür, dass alle Zahlen einer Spalte untereinander stehen. Der Operator & erlaubt durch die zwei Definitionen, dass die Matrix links oder rechts einer Zeichenkette stehen darf.


'...\Klassendesign\Operatoren\Zeichenketten.vb

Option Strict On 
Namespace Klassendesign 
  Class Matrix 
    Private val(,) As Double 
    Sub New(ByVal val(,) As Double) 
      Me.val = val 
    End Sub

    Function Append(ByVal str As String) As String 
      Dim ein As String = _ 
        Text.RegularExpressions.Regex.Replace(str, ".", " ") 
      For row As Int32 = 0 To val.GetUpperBound(0) 
        For col As Int32 = 0 To val.GetUpperBound(1) 
          str += val(row, col).ToString("##0.0").PadLeft(6) 
        Next 
        If row < val.GetUpperBound(0) Then _ 
          str += Environment.NewLine & ein 
      Next 
      Return str 
    End Function

    Public Shared Operator &(ByVal lhs As Matrix, ByVal rhs As String) _ 
    As String 
      Return lhs.Append(rhs) 
    End Operator

    Public Shared Operator &(ByVal lhs As String, ByVal rhs As Matrix) _ 
    As String 
      Return rhs.Append(lhs) 
    End Operator 
  End Class 
  ... 
End Namespace

Eine Matrix auszugeben wird damit sehr einfach:


'...\Klassendesign\Operatoren\Zeichenketten.vb

Option Strict On 
Namespace Klassendesign 
  ... 
  Module Zeichenketten 
    Sub Test() 
      Dim M As Matrix = New Matrix(New Double(,) _ 
        {{17.8, –25, 34.1},{9.1, 73.4, 82},{0, –3.4, –5.1}}) 
      Console.WriteLine("Matrix " & M & " und mehr ...") 
      Console.ReadLine() 
    End Sub 
  End Module 
End Namespace

Die Ausgabe zeigt die Werte zweidimensional und fügt sie nahtlos ein.

Matrix   17.8 –25.0  34.1 
          9.1  73.4  82.0 
          0.0  –3.4  –5.1 und mehr ...

Rheinwerk Computing - Zum Seitenanfang

3.11.2 Überladung Zur nächsten ÜberschriftZur vorigen Überschrift

Bei der Definition eines Operators sollten Sie darauf achten, dass alle für Sie interessanten Parametertypen erfasst werden. Der Fall, der einem als Erstes in den Sinn kommt, hat als Parameter nur Werte vom Typ der definierenden Klasse. Aber auch die Kombination mit Werten eines anderen Typs ist häufig sinnvoll. Beispielhaft zeigt das nächste Codefragment nicht nur die Addition zweier Vektoren, sondern auch die Addition eines Vektors und eines Skalars (Zahl), der links oder rechts vom Vektor stehen darf. Insgesamt werden also drei Definitionen des Operators gebraucht. Um den Quelltext kurz zu halten, sind Überprüfungen auf Nullreferenzen und gleiche Länge der Vektoren weggelassen.


'...\Klassendesign\Operatoren\Ueberladung.vb

Option Strict On 
Namespace Klassendesign 
  Class Vek 
    Private val() As Short 
    Sub New(ByVal val() As Short) 
      Me.val = val 
    End Sub

    Shared Function Add(ByVal v1() As Short, ByVal v2() As Short) As Short() 
      Dim res() As Short = CType(v1.Clone(), Short()) 
      Dim val(v1.Length – 1) As Short 
      For no As Integer = 0 To v1.Length – 1 
        val(no) = v1(no) + v2(Math.Min(no, v2.Length – 1)) 
      Next 
      Return val 
    End Function

    Function ToString() As String 
      Dim str As String = "|" 
      For Each d As Double In val : str += d & "|" : Next 
      Return str 
    End Function

    Public Shared Operator +(ByVal lhs As Vek, ByVal rhs As Vek) As Vek 
      Return New Vek(Add(lhs.val, rhs.val)) 
    End Operator

    Public Shared Operator +(ByVal lhs As Vek, ByVal rhs As Short) As Vek 
      Return New Vek(Add(lhs.val, New Short() {rhs})) 
    End Operator

    Public Shared Operator +(ByVal lhs As Short, ByVal rhs As Vek) As Vek 
      Return rhs + lhs 
    End Operator 
  End Class 
  ... 
End Namespace

Der Plus-Operator lässt sich nun ganz normal verwenden:


'...\Klassendesign\Operatoren\Ueberladung.vb

Option Strict On 
Namespace Klassendesign 
  ... 
  Module Überladung 
    Sub Test() 
      Dim V As Vek = New Vek(New Short() {17, –25, 34}) 
      Console.WriteLine("V   {0}", V.ToString()) 
      Console.WriteLine("V+V {0}", (V + V).ToString()) 
      Console.WriteLine("V+3 {0}", (V + 3).ToString()) 
      Console.WriteLine("3+V {0}", (3 + V).ToString()) 
      Console.ReadLine() 
    End Sub 
  End Module 
End Namespace

Die Ausgabe bestätigt die richtige Arbeitsweise des Operators:

V   |17|-25|34| 
V+V |34|-50|68| 
V+3 |20|-22|37| 
3+V |20|-22|37|

Hinweis
Bei nullbaren Werttypen werden gegebenenfalls auch die korrespondierenden nicht-nullbaren Versionen einer Operatordefinition berücksichtigt. Diese Typen werden in Abschnitt 4.5, »Werttypen mit dem Wert Nothing«, beschrieben.



Rheinwerk Computing - Zum Seitenanfang

3.11.3 Vergleich Zur nächsten ÜberschriftZur vorigen Überschrift

Im Gegensatz zu vielen anderen Operatoren müssen korrespondierende Vergleichsoperationen gemeinsam überladen werden.

    • = und <>
    • > und <
    • >= und <=

Im folgenden Beispiel wird die Länge eines Ländernamens stärker gewichtet als die alphabetische Reihenfolge: Kurze Namen erscheinen vor langen. Es wird nur ein Operator explizit kodiert, der entgegengesetzte Operator (das Antonym) ruft die Operatormethode auf und negiert das Ergebnis. Das garantiert, dass sich die gegensätzlichen Operatoren exakt ergänzen.


'...\Klassendesign\Operatoren\Vergleich.vb

Option Strict On 
Namespace Klassendesign 
  Class Land 
    Private name As String 
    Sub New(ByVal name As String) 
      Me.name = name 
    End Sub

    Public Shared Operator <(ByVal l As Land, ByVal r As Land) As Boolean 
      Return l.name.Length <= r.name.Length AndAlso l.name < r.name 
    End Operator

    Public Shared Operator >(ByVal l As Land, ByVal r As Land) As Boolean 
      Return Not op_LessThan(l, r)     ' = Not l < r 
    End Operator

    Shared Sub Test() 
      Dim L1 As Land = New Land("Finnland") 
      Dim L2 As Land = New Land("Island") 
      Dim L3 As Land = New Land("Schweden") 
      Console.WriteLine("{0}-{1}-{2}", L1.name, L2.name, L3.name) 
      Console.WriteLine("Namen 1<2: {0}", L1.name < L2.name) 
      Console.WriteLine("Namen 1<3: {0}", L1.name < L3.name) 
      Console.WriteLine("Länder 1<2: {0}", L1 < L2) 
      Console.WriteLine("Länder 1<3: {0}", L1 < L3) 
      Console.ReadLine() 
    End Sub 
  End Class 
End Namespace

Rheinwerk Computing - Zum Seitenanfang

3.11.4 Typumwandlung mit CType: Widening und Narrowing Zur nächsten ÜberschriftZur vorigen Überschrift

Umwandlungen im weiteren Sinne begegnen uns oft im täglichen Leben. Wenn wir zum Beispiel im Fischladen eigentlich Fisch kaufen wollten, der Laden aber geschlossen ist und wir dennoch nicht unverrichteter Dinge nach Hause gehen wollen, gibt es zwei Möglichkeiten: Entweder begnügen wir uns mit einer Fischdose aus dem Supermarkt, oder wir gehen im Restaurant essen. In Hinblick auf das geplante Essen ist der Umstieg auf ein Restaurant ohne Verlust möglich, während die Dosenvariante die Qualität des Essens mindert. In der Softwaretechnik stehen wir manchmal vor ähnlichen Problemen. Erwartet eine Funktion eine ganze Zahl und soll eine Fließkommazahl als Parameter verwendet werden, können wir diese explizit mittels des Operators CType vor dem Aufruf unter Verlust der Nachkommastellen umwandeln (entspricht der Fischdose). Die andere Richtung, von der ganzen Zahl zur Fließkommazahl, ist verlustfrei möglich und wird auch oft gebraucht. Normalerweise machen wir uns darüber keine Gedanken, da die Umwandlung implizit (automatisch) erfolgt.

Bei der Definition von Konvertierungsoperatoren mit CType ist Folgendes zu beachten:

  • Entweder der Start- oder der Zieltyp muss mit der Klasse übereinstimmen, in der der Operator definiert ist.
  • Widening CType beschreibt eine implizite Konvertierung, die der Compiler automatisch verwendet.
  • Narrowing CType beschreibt eine explizite Konvertierung, die expressis verbis im Quelltext stehen muss.
  • Operatoren müssen sich durch mehr als nur Narrowing oder Widening unterscheiden.
  • Konvertierungen, die Ausnahmen auslösen oder verlustbehaftet sein können, sollten mit Narrowing als explizit gekennzeichnet werden.

Hinweis
Der Konvertierungsoperator CType ist die einzige Stelle, wo der Typ des Rückgabewerts Teil der Signatur ist.


Das nächste Codefragment zeigt als Beispiel eine Autovermietung, bei der zwei Kunden bestellen. Zurzeit sind nur einige Ford Mondeo verfügbar, was sich in der Bestellmethode ausdrückt, die nur diesen Wagentyp entgegennimmt. Der erste Kunde bestellt mit einem Maybach ein teures Auto. Da ein Mondeo weniger Komfort bedeutet, muss durch eine explizite Umwandlung mit CType die Bestellung ermöglicht werden. Demgegenüber bestellt der zweite Kunde eine Ente. Der Vermieter kann dem Kunden ohne Weiteres einen Mondeo geben, da dieser hochwertiger als das bestellte Auto ist. Die Umwandlung erfolgt implizit beim Aufruf der Bestellmethode. Ob Sie die Typkonvertierungen auf zwei Klassen verteilen oder nicht, ist Geschmackssache. Wichtig ist, dass Sie dieselbe Konvertierung nicht durch zwei Klassen doppelt zur Verfügung stellen (die vom Compiler generierte Fehlermeldung ist nicht sehr aussagekräftig).


'...\Klassendesign\Operatoren\Konvertierungen.vb

Option Strict On 
Namespace Klassendesign

  Class Ente : End Class

  Class Maybach 
    Public Shared Narrowing Operator CType(ByVal auto As Maybach) As Mondeo 
      Console.Write("mit Rückerstattung ") 
      Return New Mondeo() 'um es einfach zu halten 
    End Operator 
  End Class

  Class Mondeo 
    Public Shared Widening Operator CType(ByVal auto As Ente) As Mondeo 
      Console.Write("auf Kosten des Hauses ") 
      Return New Mondeo() 'um es einfach zu halten 
    End Operator 
  End Class

  Module Autovermietung 
    Sub Bestellen(ByVal auto As Mondeo) 
      Console.WriteLine("Mondeo erhalten.") 
    End Sub 
    Sub Test() 
      Console.Write("Maybach bestellt und ") 
      Bestellen(CType(New Maybach(), Mondeo))      'explizit – Narrowing 
      Console.Write("Ente bestellt und ") 
      Bestellen(New Ente())                        'implizit – Widening 
      Console.ReadLine() 
    End Sub 
  End Module 
End Namespace

Die Ausgabe »mit Rückerstattung« zeigt, dass für den ersten Kunden die Konvertierung mit Narrowing verwendet wurde, während beim zweiten Kunden die Widening-Variante »auf Kosten des Hauses« ausgibt.

Maybach bestellt und mit Rückerstattung Mondeo erhalten. 
Ente bestellt und auf Kosten des Hauses Mondeo erhalten.

Eine Stolperfalle gibt es bei einer For Each-Schleife. Sie nutzt ausnahmsweise auch explizite Konvertierungen automatisch. Das folgende Codefragment nutzt die einzig vorhandene Konvertierung. Sie ist explizit.


'...\Klassendesign\Operatoren\ForEach.vb

Option Strict On 
Namespace Klassendesign 
  Class Zahl 
    Public Shared Narrowing Operator CType(ByVal f As Zahl) As Short 
      Return 0 'um es einfach zu halten 
    End Operator 
  End Class 
  Module ForEach 
    Sub Test() 
      For Each a As Short In New Zahl() {New Zahl()} 
        Console.Write(a & " ") 
      Next 
      Console.ReadLine() 
    End Sub 
  End Module 
End Namespace

Rheinwerk Computing - Zum Seitenanfang

3.11.5 Wahrheitswerte: IsTrue und IsFalse Zur nächsten ÜberschriftZur vorigen Überschrift

Ob ein Wert als Wahrheitswert betrachtet wird, hängt davon ab, ob er eines der folgenden Kriterien erfüllt, wobei das erste zutreffende Kriterium genommen wird (Boolean? ist auch erlaubt, siehe Abschnitt 4.5, »Werttypen mit dem Wert Nothing«):

  • Der Wert ist schon Boolean.
  • Der Wert kann implizit in Boolean konvertiert werden.
  • Der Wert definiert die Pseudooperatoren IsTrue und IsFalse.

Möchten Sie die letzte Variante wählen, ist Folgendes zu beachten:

  • IsTrue und IsFalse müssen zusammen überladen werden.
  • Boolean ist zwingend als Typ der Rückgabe zu verwenden (Boolean? geht nicht).
  • Zur Benutzung von AndAlso und OrElse müssen And und Or so definiert sein, dass beide Parameter und das Ergebnis vom Typ der definierenden Klasse sind (natürlich können zusätzlich weitere Signaturen definiert sein).

Das folgende Codefragment zeigt eine Klasse Ort, die die Operatoren IsTrue, IsFalse, Or und And definiert. Jeder der Operatoren macht sich beim Aufruf durch eine Konsolenausgabe bemerkbar, um zu prüfen, ob und in welcher Reihenfolge die Operatoren angesprochen werden. Die Boolean-Operatoren geben außerdem an, welches Objekt (erster Buchstabe) mit welchem Ergebnis (J oder N) gerade getestet wird. Bei den Orten interessieren hier die Temperaturen, sodass »Kuba« als »wahr« und »Island« als »falsch« angesehen werden.


'...\Klassendesign\Operatoren\Wahrheitswerte.vb

Option Strict On 
Namespace Klassendesign 
  Class Ort 
    Friend ReadOnly wo As String 
    Sub New(ByVal wo As String) 
      Me.wo = wo 
    End Sub

    Public Shared Operator IsTrue(ByVal o As Ort) As Boolean 
      Console.Write(o.wo(0) & ":IsTrue :" & If(o.wo = "Kuba", "J ", "N ")) 
      Return o.wo = "Kuba" 
    End Operator

    Public Shared Operator IsFalse(ByVal o As Ort) As Boolean 
      Console.Write(o.wo(0) & ":IsFalse:" & If(o.wo = "Island", "J ", "N ")) 
      Return o.wo = "Island" 
    End Operator

    Public Shared Operator Or(ByVal a As Ort, ByVal b As Ort) As Ort 
      Console.Write("Op_| ") 
      Return If(a.wo = "Kuba" Or b.wo = "Kuba", a, b) 
    End Operator

    Public Shared Operator And(ByVal a As Ort, ByVal b As Ort) As Ort 
      Console.Write("Op_& ") 
      Return If(a.wo <> "Island" And b.wo <> "Island", a, b) 
    End Operator 
  End Class 
  ... 
End Namespace

Der Test der Operaratoren erfolgt mit einer Liste von Länderpaaren, die in einem Array von Länderarrays abgelegt wird. Die Art der Erzeugung ist hier unwichtig; die Syntax wird in Abschnitt 6.4, »LINQ« erläutert. Der Test innerhalb der Schleife spricht zuerst im ersten Argument der beiden ersten If-Operatoren die Objekte direkt als Wahrheitswerte an. Danach folgt der Test der Logikoperatoren.


'...\Klassendesign\Operatoren\Wahrheitswerte.vb

Option Strict On 
Namespace Klassendesign 
  ... 
  Module Wahrheitswerte 
    Sub out(ByVal str As String, ByVal newline As Boolean) 
      Console.Write(str.PadRight(16) & If(newline, Environment.NewLine, "")) 
    End Sub

    Sub Test() 
      Const h As String = "warm" 
      Const k As String = "kalt" 
      Dim wo() As Ort = New Ort() _ 
        {New Ort("Kuba"), New Ort("Island"), New Ort("Japan")} 
      'Kombination jeder mit jedem: cross join 
      Dim orte()() As Ort = _ 
        (From o1 In wo From o2 In wo Select New Ort() {o1, o2}).ToArray()

      For Each o() As Ort In orte 
        out((o(0).wo & " ist " & If(o(0), h, k)).PadRight(21), False) 
        out((o(1).wo & " ist " & If(o(1), h, k)).PadRight(21), True) 
        out("Or  ist " & If(o(0) Or o(1), h, k), False) 
        out("OrElse  ist " & If(o(0) OrElse o(1), h, k), True) 
        out("And ist " & If(o(0) And o(1), h, k), False) 
        out("AndAlso ist " & If(o(0) AndAlso o(1), h, k), True) 
        Console.WriteLine() 
      Next 
      Console.ReadLine() 
    End Sub

  End Module 
End Namespace

Die Ausgabe zeigt das Verhalten der Operatoren:

  • Normale Logikoperatoren (And und Or): Der Operator wird aufgerufen, und das Ergebnis, das vom Typ der Klasse (Ort) ist, wird mit IsTrue auf den Wahrheitsgehalt getestet.
  • Kurzschlussoperatoren (AndAlso und OrElse): Der erste Operand wird bei AndAlso mit IsFalse und bei OrElse mit IsTrue getestet. Steht das Ergebnis fest, wird (warum auch immer) der Operand erneut getestet; ist das Ergebnis noch unbestimmt, wird der korrespondierende normale Logikoperator aufgerufen.
K:IsTrue :J Kuba ist warm      K:IsTrue :J Kuba ist warm 
Op_| K:IsTrue :J Or  ist warm  K:IsTrue :J K:IsTrue :J OrElse  ist warm 
Op_& K:IsTrue :J And ist warm  K:IsFalse:N Op_& K:IsTrue :J AndAlso ist warm

K:IsTrue :J Kuba ist warm      I:IsTrue :N Island ist kalt 
Op_| K:IsTrue :J Or  ist warm  K:IsTrue :J K:IsTrue :J OrElse  ist warm 
Op_& I:IsTrue :N And ist kalt  K:IsFalse:N Op_& I:IsTrue :N AndAlso ist kalt

K:IsTrue :J Kuba ist warm      J:IsTrue :N Japan ist kalt 
Op_| K:IsTrue :J Or  ist warm  K:IsTrue :J K:IsTrue :J OrElse  ist warm 
Op_& K:IsTrue :J And ist warm  K:IsFalse:N Op_& K:IsTrue :J AndAlso ist warm

I:IsTrue :N Island ist kalt    K:IsTrue :J Kuba ist warm 
Op_| I:IsTrue :N Or  ist kalt  I:IsTrue :N Op_| I:IsTrue :N OrElse  ist kalt 
Op_& K:IsTrue :J And ist warm  I:IsFalse:J I:IsTrue :N AndAlso ist kalt

I:IsTrue :N Island ist kalt    I:IsTrue :N Island ist kalt 
Op_| I:IsTrue :N Or  ist kalt  I:IsTrue :N Op_| I:IsTrue :N OrElse  ist kalt 
Op_& I:IsTrue :N And ist kalt  I:IsFalse:J I:IsTrue :N AndAlso ist kalt

I:IsTrue :N Island ist kalt    J:IsTrue :N Japan ist kalt 
Op_| J:IsTrue :N Or  ist kalt  I:IsTrue :N Op_| J:IsTrue :N OrElse  ist kalt 
Op_& J:IsTrue :N And ist kalt  I:IsFalse:J I:IsTrue :N AndAlso ist kalt

J:IsTrue :N Japan ist kalt     K:IsTrue :J Kuba ist warm 
Op_| J:IsTrue :N Or  ist kalt  J:IsTrue :N Op_| J:IsTrue :N OrElse  ist kalt 
Op_& J:IsTrue :N And ist kalt  J:IsFalse:N Op_& J:IsTrue :N AndAlso ist kalt

J:IsTrue :N Japan ist kalt     I:IsTrue :N Island ist kalt 
Op_| I:IsTrue :N Or  ist kalt  J:IsTrue :N Op_| I:IsTrue :N OrElse  ist kalt 
Op_& I:IsTrue :N And ist kalt  J:IsFalse:N Op_& I:IsTrue :N AndAlso ist kalt

J:IsTrue :N Japan ist kalt     J:IsTrue :N Japan ist kalt 
Op_| J:IsTrue :N Or  ist kalt  J:IsTrue :N Op_| J:IsTrue :N OrElse  ist kalt 
Op_& J:IsTrue :N And ist kalt  J:IsFalse:N Op_& J:IsTrue :N AndAlso ist kalt

Rheinwerk Computing - Zum Seitenanfang

3.11.6 Grafikbibliothek: Addition und Umwandlung von Rechtecken 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.10.6, »Grafikbibliothek: Größenänderungen von Rechtecken überwachen«, erweiterte Grafikanwendung. Der neu hinzukommende Additionsoperator erzeugt ein Rechteck, das die beiden Operanden umschließt. Bei der Typkonvertierung von Double nach Rechteck wird die Zahl als Fläche aufgefasst und ein flächengleiches Rechteck erzeugt.


'...\Klassendesign\Graphik\Operatoren.vb

Option Explicit On 
Namespace Klassendesign 
  Partial Public Class Rechteck

    Shared Operator +(ByVal r1 As Rechteck,ByVal r2 As Rechteck) As Rechteck 
      Return New Rechteck(Math.Max(r1.a, r2.a), Math.Max(r1.b, r2.b)) 
    End Operator

    Shared Widening Operator CType(ByVal fläche As Double) As Rechteck 
      Return New Rechteck(Math.Sqrt(fläche), Math.Sqrt(fläche)) 
    End Operator

  End Class 
End Namespace

Zum Test werden zwei Rechtecke erzeugt – das zweite durch die implizite Anwendung der definierten Typumwandlung. Danach werden die beiden Rechtecke mittels des neu definierten Additionsoperators zusammengefasst. Schließlich werden die Größen aller drei Rechtecke ausgegeben.


'...\Klassendesign\Zeichner\Operatoren.vb

Option Explicit On 
Namespace Klassendesign 
  Partial Class Zeichner 
    Sub Operatoren() 
      Dim r1 As New Rechteck(9, 2) 
      Dim r2 As Rechteck = 49 
      Dim r3 As Rechteck = r1 + r2 
      r1.Größe() : r2.Größe() : r3.Größe() 
    End Sub 
  End Class 
End Namespace

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

Dimension des Rechtecks: 9x2 
Dimension des Rechtecks: 7x7 
Dimension des Rechtecks: 9x7

Die nächste Erweiterung erfolgt in Abschnitt 3.13.9, »Grafikbibliothek: neue Vielecke«.



Ihre Meinung

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

<< zurück
  Zum Rheinwerk-Shop
Zum Rheinwerk-Shop: Visual Basic 2008
Visual Basic 2008
Jetzt Buch bestellen


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

 Buchempfehlungen
Zum Rheinwerk-Shop: Visual Basic 2012






 Visual Basic 2012


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






 Schrödinger
 programmiert C++


Zum Rheinwerk-Shop: IT-Handbuch für Fachinformatiker






 IT-Handbuch für
 Fachinformatiker


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






 Professionell
 entwickeln mit
 Visual C# 2012


Zum Rheinwerk-Shop: Windows Presentation Foundation






 Windows Presentation
 Foundation


 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und der Schweiz
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.


Nutzungsbestimmungen | Datenschutz | Impressum

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

Cookie-Einstellungen ändern