Operatorenprozeduren können, richtig eingesetzt, eine enorme Erleichterung für den Entwickler darstellen. Gleichzeitig sollten Sie aber auch einige Dinge beherzigen, bei denen Operatorenprozeduren dafür verantwortlich sein können, dass sich durch ihre Implementierung Fehler einschleichen.

Aufgepasst bei der Verwendung von Referenztypen

In unserem Beispiel haben wir die Operatorenprozeduren in eine Struktur eingebaut. Damit handelt es sich automatisch um einen Wertetyp, den auch die Operatorenprozeduren verarbeiten. Nun schauen Sie sich eine der Rechenoperatorenprozeduren noch einmal genauer an:

Public Shared Operator +(ByVal sstring1 As SuperString, ByVal sstring2 As SuperString) As SuperString
    Return sstring1.Addieren(sstring2)
End Operator

Die Addieren-Funktion wird hier auf sstring1 angewendet und Addieren liefert – wenn Sie sich den entsprechenden Code anschauen – ohnehin eine neue Instanz von SuperString zurück. Aber das muss nicht so sein. Manche Implementierungen »neigen dazu«, das Objekt selbst zu verändern. Würde Addieren das machen – wäre Addieren also eine Methode, die kein Funktionsergebnis liefern würden –, würde der entsprechende Code der Operatorenprozedur vielleicht so aussehen:

Public Shared Operator +(ByVal sstring1 As SuperString, ByVal sstring2 As SuperString) As SuperString
    sstring1.Addieren(sstring2)
    Return sstring1
End Operator

Solange es sich bei den Werten, die sstring1.Addieren manipuliert, um Wertetypen handelt, und solange sstring1 selbst ein Wertetyp ist, hat eine solche Prozedur immer noch nichts Gefährliches an sich. Schlimm kann es nur dann werden, wenn Addieren einen Referenztypen manipuliert und es sich bei sstring1 selbst ebenfalls um einen Referenztypen handeln würde.

In diesem Fall würden Sie nämlich als Parameter in sstring1 im Grunde genommen einen Zeiger auf die eigentlichen Objektdaten entgegennehmen. Das anschließende Addieren würde also keine Kopie von sstring1 verändern, sondern die einzig existierende Instanz – die ursprünglich im aufrufenden Code vor dem Operator gestanden hätte. Sie würden damit in der Objektvariablen, die Sie als Operanden übergeben, und in der Objektvariablen, der Sie den Ausdruck zuweisen, das gleiche Ergebnis vorfinden. Zur Verdeutlichung (und bei dem folgenden Code nehmen wir an, dass es sich beim Typ, für den Operatoren definiert sind, um einen Referenztyp handelt):

Dim objVar1 As New RefType(10)
Dim objVar2 As New RefType(20)
Dim objVar3 As RefType
objVar3 = ObjVar1 + objVar2

Vorausgesetzt, RefType würde in der Lage sein, Zahlen zu addieren. Dann würde das Ergebnis 30 – das eben vorgestellte Szenario angenommen – nach Abschluss nicht nur in objVar3, sondern auch in objVar1 »stehen«. Und im Grunde genommen ist es sogar noch schlimmer: Da objVar3 und objVar1 auf die gleichen Daten zeigen, würde eine Veränderung von objVar1 immer auch eine Veränderung von objVar3 nach sich ziehen.

Gerade bei Operatorenprozeduren, bei denen Sie ein solches Verhalten am wenigsten erwarten, sollten Sie daher darauf achten, dass diese als Rückgabewert immer eine neue Instanz ihres Typs zurückgeben, wenn sie Referenztypen verarbeiten

Aufgepasst bei Mehrdeutigkeiten bei der Auflösung von Signaturen

In unserer Beispielklasse ist, nachdem wir die Typkonvertierungsfunktionen vollständig implementiert haben, Folgendes erlaubt:

einSuperString = einSuperString + "Klaus"

Auf den ersten Blick mag das merkwürdig erscheinen, denn für die Addition haben wir keine Überladungsversion implementiert, die einen »einfachen« String akzeptieren würde. Dennoch meldet der Visual Basic-Compiler keinen Fehler. Und das zurecht, denn: Die einzige Operatorenprozedur, die das Addieren mit dem +-Operator erlaubt, nimmt als zweiten Parameter eine Variable vom Typ SuperString entgegen. Der wiederum verfügt aber über einen impliziten Typkonvertierungsmechanismus, der einen normalen String in einen SuperString umwandeln kann. Der Compiler macht also das einzig Richtige: Er sorgt dafür, dass »Klaus« implizit zunächst in einen SuperString konvertiert wird, und dieser SuperString wird anschließend der Additions-Operatorenprozedur übergeben.

Was passiert aber, wenn es sowohl eine implizite Konvertierung von String in SuperString als auch eine überladene Version des Additionsoperators gibt, die Strings akzeptiert? In diesem Fall wird diese Additionsoperationsprozedur verwendet.

Fehler können sich aber – Sie ahnen es schon – dann einschleichen, wenn beide Routinen auf unterschiedliche Weise vorgehen, um den String in einen SuperString zu konvertieren. Die anschließende Fehlersuche bei Fehlern in komplexen Typen kann sich dann unter Umständen als sehr mühselig entpuppen.

Tipp Es empfiehlt sich also in jedem Fall, die möglichen Parameterkombinationen durchzuprobieren, herauszufinden, wo welche Konvertierung wirklich stattfindet, und alle Operatorenprozeduren dazu, am besten Schritt für Schritt, mit dem Visual Studio-Debugger zu durchlaufen.

Mehr zu diesem Thema in: Visual Basic 2010 das Entwicklerbuch von Klaus Löffelmann, erhältlich bei Amazon auch auf Englisch, und bei Microsoft Press. Möchten Sie Klaus Löffelmann oder das ActiveDevelop-Team für professionelle Software-Entwicklungsprojekte (Migration, C#, Visual Basic.NET) buchen, informieren Sie sich auf www.activedevelop.de

klauslo am 04. Februar 2012

Tags: | Categories: Operatorenprozeduren