Dieses Kapitel fasst die fundamentalen Klassen Object, String, StringBuilder, DateTime und TimeSpan zusammen und geht auf Besonderheiten ein, die nützlich für fortgeschrittene Programmierung sind.
10 Einige Basisklassen
10.1 Object 

Diese Klasse ist als Wurzel der Klassenhierarchie die einzige, die von keiner anderen Klasse abgeleitet ist. Wenn Sie keine explizite Elternklasse angeben, fügt der Compiler implizit Object ein. Die Funktionalität dieses gemeinsamen Vorfahrs teilen alle Objekte.
10.1.1 Methoden 

Sieben Methoden vererbt die Klasse Object an Subklassen: fünf öffentliche und zwei, die mit Protected auf Nachfahren beschränkt sind (siehe Tabelle 10.1).
Methode | Beschreibung | |
New |
Parameterloser Konstruktor |
|
Equals |
Gibt an, ob das gegebene Objekt diesem gleich ist. |
O |
Finalize |
Aufgerufen bei Zerstörung des Objekts (z. B. Ressourcenfreigabe) |
P |
GetHashCode |
Objektspezifischer Identifizierer (nicht garantiert eindeutig) |
O |
GetType |
Eine Type-Instanz, die den Typ des Objekts beschreibt |
|
MemberwiseClone |
Dupliziert die aktuelle Instanz und liefert die Referenz der Kopie. |
P |
ReferenceEquals |
Gibt an, ob die beiden Referenzen auf dasselbe Objekt zeigen. |
S |
ToString |
Liefert den vollqualifizierenden Namen einer Klasse. |
O |
Hinweis |
Wenn Equals Objekte inhaltlich vergleichen soll, muss die zugrunde liegende Klasse die Methode Equals neu definieren (siehe Abschnitt 3.14.5, »Equals«) oder den Gleichheitsoperator = überladen (siehe Abschnitt 3.11.3, »Vergleich«). |
Den Nutzen der Methode ToString habe ich bereits in Abschnitt 3.14.6, »ToString«, angedeutet. Hier möchte ich nur noch auf das Standardverhalten hinweisen, das den vollqualifizierten Klassennamen liefert, ohne Objekte derselben Klasse zu unterscheiden. Viele Klassen überschreiben das Verhalten, zum Beispiel Zahlenprimitive wie Double und Zeichenketten.
Public Overridable Function ToString() As String |
Finalize wurde bereits in Abschnitt 3.16.2, »Destruktoren«, gezeigt. Die anderen Methoden werden in den folgenden Abschnitten behandelt.
10.1.2 GetType 

Zur Laufzeit liegen für jeden Datentyp Metainformationen vor, die in einem Type-Objekt gespeichert sind.
Public Function [GetType]() As Type |
Um den Rahmen dieses Kapitels nicht zu sprengen, zeigt das folgende Beispiel nur eine ganz einfache Typanalyse. Mit den Klassen im Namensraum System.Reflection können Sie zur Laufzeit mit etwas Aufwand sogar neue Datentypen erzeugen.
'...\Basisklassen\KlasseObject\GetType.vb |
Option Strict On Namespace Basisklassen Class Kind Public Feld As Integer = 9 End Class Class Enkel : Inherits Kind : End Class Module [GetType] Private Sub Eltern(ByVal type As Type) If type IsNot GetType(Object) Then Eltern(type.BaseType) Console.Write(type.Name & " ") End Sub Sub Test() Dim kind As New Enkel() Dim kindertyp As Type = kind.GetType() Console.WriteLine(kindertyp.Assembly.FullName) Eltern(kindertyp) For Each fi As System.Reflection.FieldInfo In kindertyp.GetFields() Console.Write(fi.Name & "=" & fi.GetValue(kind).ToString()) Next Console.ReadLine() End Sub End Module End Namespace
10.1.3 Gleichheit 

Wie in Abschnitt 3.1.9, »Datentypen«, bereits erläutert wurde, muss bei Gleichheit von Objekten zwischen Objektreferenzen auf identische Objekte und Objekten mit gleichen (oder sogar denselben) Werten unterschieden werden. Sowohl Equals als auch ReferenceEquals in der Klasse Object verstehen unter Gleichheit die Identität zweier Referenzen. Für einen inhaltlichen Vergleich muss die Methode Equals in einer Kindklasse überschrieben werden.
Public Overridable Function Equals(obj As Object) As Boolean Public Shared Function Equals(objA As Object, objB As Object) As Boolean Public Shared Function ReferenceEquals(a As Object, b As Object) As Boolean |
Hinweis |
Auch wenn die Methode Equals der Schnittstelle IEquatable(Of T) als typsicher bevorzugt werden sollte, kann sie die Methode in Object nicht ersetzen, sondern nur ergänzen. |
Was Sie als »gleich« ansehen, bleibt Ihnen überlassen. In der Regel werden die Werte der Felder herangezogen. Im folgenden Beispiel hat die Klasse Ball keine Felder, und verschiedene Bälle werden nicht unterschieden; Equals gibt True zurück. So hält der Torwart einen Ball und nicht den Ball. Bitte beachten Sie den Test auf eine Nullreferenz und korrekten Typ in der Methode Equals, die als Parametertyp immer Object hat.
'...\Basisklassen\KlasseObject\Feldgleichheit.vb |
Option Strict On Namespace Basisklassen Module Feldgleichheit Class Ball Public Overrides Function Equals(ByVal obj As Object) As Boolean If obj Is Nothing OrElse Not TypeOf obj Is Ball Then Return False Return True End Function End Class Class Spieler Friend ball As Ball End Class Sub Test() Dim regulär As New Ball(), zuviel As New Ball() Dim stürmer As New Spieler : stürmer.ball = regulär Dim torwart As New Spieler : torwart.ball = zuviel Console.WriteLine("Stürmerball ähnelt Torwartball: {0}", _ stürmer.ball.Equals(torwart.ball)) Console.WriteLine("Stürmerball ist Torwartball: {0}", _ Object.ReferenceEquals(stürmer.ball, torwart.ball)) Console.ReadLine() End Sub End Module End Namespace
Der Schiedsrichter wird sich wohl auf den zweiten Vergleich stützen.
Stürmerball ähnelt Torwartball: True Stürmerball ist Torwartball: False
Nicht immer wird die Methode Equals zur Definition von Gleichheit herangezogen. Viele Funktionen nutzen aus Effizienzgründen die Methode GetHashCode, zum Beispiel einige der Auflistungen:
Public Overridable Function GetHashCode() As Integer |
Wenn Sie Ihren Klassen eine eigene Vorstellung von Gleichheit mitgeben wollen, gilt daher:
Equals() und GetHashCode() sollten immer gemeinsam überschrieben werden. |
Das folgende Beispiel weist auf das Problem hin. Obwohl die verwendete Auflistung GetHashCode zur Sortierung benutzt, müssen beide Methoden in Ware überschrieben werden. Wird nur eine weggelassen, wird das Objekt nach der Änderung nicht mehr gefunden.
'...\Basisklassen\KlasseObject\Boxing.vb |
Option Strict On Namespace Basisklassen Module Boxing Structure Ware Public Menge, Preis As Double Public Overrides Function Equals(ByVal obj As Object) As Boolean If obj Is Nothing OrElse Not TypeOf obj Is Ware Then Return False Return CType(obj, Ware).Preis.Equals(Preis) End Function Public Overrides Function GetHashCode() As Integer Return Preis.GetHashCode() End Function End Structure Sub Test() Dim waren As New HashSet(Of Ware) Dim mehl As New Ware() : mehl.Preis = 0.52 : waren.Add(mehl) Console.WriteLine("Mehl gefunden: {0}", waren.Contains(mehl)) mehl.Menge = 0.54 Console.WriteLine("Mehl gefunden: {0}", waren.Contains(mehl)) Console.ReadLine() End Sub End Module End Namespace
Der Compiler sucht sich für einen Methodenaufruf immer den am besten passenden Typ heraus. Aus diesem Grund wurde die Schnittstelle IEquatable(Of T) geschaffen. Sie stellt das typisierte Pendant zu Equals() dar. Diese Möglichkeit entbindet Sie aber nicht von der Notwendigkeit, auch die allgemeine Equals()-Methode zu definieren (und damit auch GetHashCode()), denn nicht in jeder Situation hat der Compiler genügend Informationen, um die am besten passende Methode zu wählen.
10.1.4 Objekte kopieren 

Die Methode MemberwiseClone kopiert ein vorhandenes Objekt und liefert die Referenz auf die Kopie:
Protected Function MemberwiseClone() As Object |
Von allen Feldern wird eine sogenannte flache Kopie erzeugt. Speichert ein Feld eine Objektreferenz, wird die Referenz als solche kopiert, nicht aber das Objekt, auf das sie zeigt. Durch den Zugriffsmodifizierer können Sie die Methode nicht von außerhalb der Klassenhierarchie aufrufen. Für diesen Zweck gibt es die Schnittstelle ICloneable.
Public Interface ICloneable
Function Clone() As Object
End Interface |
Damit lässt sich nun einfach eine Kopierfunktion erstellen. Das folgende Beispiel nutzt MemberwiseClone, um eine flache Kopie zu erzeugen. Innerhalb von Clone wird für das Feld Clone aufgerufen, um eine tiefe Kopie zu erzeugen:
'...\Basisklassen\KlasseObject\Kopie.vb |
Option Strict On Namespace Basisklassen Module Kopie Class Gemälde : Implements ICloneable Public Wert As Single = Rnd() Public Function Clone() As Object Implements ICloneable.Clone Return Me.MemberwiseClone() End Function End Class Class Fälscher : Implements ICloneable Public obj As New Gemälde() Public Function Clone() As Object Implements ICloneable.Clone Dim kopie As Fälscher = CType(Me.MemberwiseClone(), Fälscher) kopie.obj = CType(obj.Clone(), Gemälde) Return kopie End Function End Class Sub Test() Dim meister As New Fälscher() Dim stift As Fälscher = CType(meister.Clone(), Fälscher) Console.WriteLine("Selben Fälscher {0}", meister Is stift) Console.WriteLine("Selben Gemälde {0}", meister.obj Is stift.obj) Console.WriteLine("Selben Werte {0}", meister.obj.Wert = stift.obj.Wert) Console.ReadLine() End Sub End Module End Namespace
Hinweis |
Wenn Feldvariablen Arrays speichern, müssen diese für eine tiefe Kopie erst kopiert werden, bevor die Einzelelemente geklont werden. |
Die Ausgabe zeigt, dass eine tiefe Kopie erzeugt wurde:
Selben Fälscher False Selben Gemälde False Selben Werte True