vb@rchiv
VB Classic
VB.NET
ADO.NET
VBA
C#

https://www.vbarchiv.net
Rubrik: .NET   |   VB-Versionen: VB.NET15.01.03
VB.NET: Überladen von Methoden und Eigenschaften

VB.NET ist ein Versuch, die bewährten Programmierkonzepte der vergangenen Tage mit den neuen Ansätzen von Visual Basic zu vereinen. An manch einer Stelle scheint aber der Übergang von der Vergangenheit in die Gegenwart der Programmiersprache nicht lückenlos möglich. Es entstehen syntaktische Ausdrücke die zwar vom Compiler zugelassen, aber nicht mehr im Sinne des Programmierers verwendet werden. Eine solche konzeptionelle Baustelle wollen wir am Beispiel des Überladens von Methoden und Eigenschaften in VB.NET näher inspizieren.

Autor:  Peter A. LandauBewertung:  Views:  25.176 

VB.NET ist ein Versuch, die bewährten Programmierkonzepte der vergangenen Tage mit den neuen Ansätzen von Visual Basic zu vereinen. An manch einer Stelle scheint aber der Übergang von der Vergangenheit in die Gegenwart der Programmiersprache nicht lückenlos möglich. Es entstehen syntaktische Ausdrücke die zwar vom Compiler zugelassen, aber nicht mehr im Sinne des Programmierers verwendet werden. Eine solche konzeptionelle Baustelle wollen wir am Beispiel des Überladens von Methoden und Eigenschaften in VB.NET näher inspizieren.

Der Compiler und seine Komplizen

Die Bausteine eines Softwareentwicklungssystems sind funktionell aufeinander abgestimmt. Die IntelliSense (vgl. Abb. 3) und der Compiler bilden ein Team.

Zuweilen wird deren Zusammenarbeit durch Fremdeinflüsse gehindert, insbesondere dann, wenn die Arbeitsgruppe durch ein weiteres Mitglied erweitert wird, den Programmierer.

Die Zeit für die Besinnung des Entwicklers ist reif, wenn die IntelliSense von .NET zeigt, womit der Übersetzer, der Compiler nicht durchgängig einverstanden ist.

In diesem Artikel möchten wir uns dem Überladen von Methoden und Eigenschaften primär in Visual Basic .NET (2002) widmen. Stellenweise wird die Syntax zur Erfüllung gleicher Aufgabe in VB 6.0 und VBA, Visual Basic for Applications (betrachtet: MS Office 2000) angegeben.

Im Kapitel 1 deuten wir die allgem. Prinzipien des Überladens von Elementen im Rahmen einer Programmiersprache an, und setzen diese anschließend unter Visual Basic .NET ein. Die Kapitel 3 und 4 befassen sich mit einer, unter Visual Basic .NET definierbaren Abart des Überladens. Im letzten Kapitel dieses Dokumentes versuchen wir, eben angesichts dieses denkbaren Problemfalles, eine Gesamtübersicht über das Überladen von Elementen unter VB 6.0, VBA und VB.NET (2002) anzufertigen.

Falls nicht anders lautend angegeben, liegen die Code-Ausschnitte in diesem Artikel in der VB.NET-Syntax vor.

Den Schwerpunkt dieses Artikels bildet somit eine, vereinzelt problematische Wechselbeziehung von Konzepten, die mit den Schlüsselbegriffen: Optional, ParamArray und Overloads in Visual Basic (.NET) eingeleitet werden.

1. Parameter, die Grundlage der Elementen-Polymorphie

Das Überladen von Elementen ist die "mehrfache Definition einer Funktion oder eines Operators innerhalb eines Gültigkeitsbereiches." [HGD2000, S. 605]

Diese Definition bezieht sich auf die Programmiersprache C++, in der sowohl Prozeduren, wie auch Funktionen einen Rückgabetyp aufweisen (ggf. void) und somit als Funktionen gelten. Ein Überladen von Operatoren (+=, *=, usw.) ist in VB.NET 2002 nicht möglich.

Die auf VB.NET zugeschnittene Definition lautet somit: "mehrfache Definition eines Elementes innerhalb eines Gültigkeitsbereiches" (vgl. Abb. 1; praktisch, Abb. 3).

Bei einem überladenen Element (Methode, Eigenschaft) verwendet der Compiler die Definition des Elementes für den Aufruf, die in der Anzahl, der Position der Parameter und ihren Datentypen, mit dem Elementaufruf übereinstimmt (vgl. Abb. 1).

Aufruf eines überladenen Elementes, Prinzip
Abb. 1: Aufruf eines überladenen Elementes, Prinzip

Polymorphie bedeutet Vielgestaltigkeit. Die Funktions- oder Elementen-Polymorphie steht daher für verschiedene Formen (Signaturen) einer Funktion, bzw. allgem., eines Elementes.

Die verschiedenen Elemente (Methoden, Eigenschaften) unterscheiden sich auf Grund ihrer Signatur (Name + Parameter) innerhalb eines Gültigkeitsbereiches voneinander.

Die verschiedenen Definitionen eines zu überladenen Elementes (vgl. Abb. 3, "Delta") unterscheiden sich auf Grund ihrer Parameter voneinander. Der Name des Elementes bleibt für alle Definitionen dieses Elementes innerhalb eines Gültigkeitsbereiches gleich, darin besteht die Besonderheit und der Zweck des Überladens von Methoden und Eigenschaften (, Operatoren).

Die Kombination aus dem Namen und den Parametern dient der IDentifikation einer Signatur.

Die Anzahl der Parameter, ihre Reihenfolge und die Datentypen innerhalb einer Signatur bilden den Schlüssel zur Verwendung des Überladens von Elementen. Aus diesem Grunde müssen wir näher auf den Begriff des Parameters eingehen.

1.1. By value vs. by reference

Das VB-Schlüsselwort ByVal gibt an, dass ein Argument als Wert an ein Element übergeben wird. Innerhalb des Elementes (Methode oder Eigenschaft) existiert eine Kopie des an das Element übergebenen Inhalts. Veränderungen, die an der Kopie vorgenommen werden, betreffen ausschließlich diese Kopie und nicht das Original selbst.

Das Schlüsselwort ByRef sagt hingegen aus, dass nicht eine Kopie des Originals an ein Element übergeben wird, sondern die Adresse des Speicherplatzes anstelle des Wertes. Auf diese Weise kann innerhalb des Elementes nicht die Kopie des übergebenen Inhaltes, sondern das Original selbst (über den Zeiger) bearbeitet werden.

Die Parameter werden unter VB 6.0 und VBA standardmäßig als Referenzen übergeben (ByRef), unter VB 7.0 (VB.NET) hingegen, als Wertekopien (ByVal).

1.2. By position vs. by name

Die Argumente, die Parameter eines Elementes, können in Visual Basic auf zwei Arten dem aufzurufenden Element übermittelt werden:

  • Über ihre Position im Aufruf
  • Unabhängig davon, über die Bezeichnung, den Namen des Parameters.

    Mischformen aus beiden Varianten sind denkbar und einige Besonderheiten zu beachten.

    Beispiel 1:

    Public Sub Test(ByRef A As Integer, _
      ByVal B As String, ByVal C As System.TimeSpan )
     
      ' [...]
    End Sub

    Aufruf über die Position: Test(C:=New System.TimeSpan(), A:=5, B:="SER")
    Aufruf über den Namen: Test(5, "ABC", New System.TimeSpan())

    An dieser Stelle wollen wir nicht näher auf die Einzelheiten von erzielbaren Aufrufvarianten der Operationen eingehen. Diese kleine Demonstration soll nur daran erinnern, dass die in Visual Basic (VB 6.0, VBA, VB.NET) enthaltenen Aufrufkonstellationen mannigfaltig sind.

    2. Überladen von Methoden im VB-Alltag

    Unter VB 6.0 und auch VBA ist das Überladen von Methoden und Eigenschaften nicht direkt möglich (Abb. 2). Indirekt führt die Benutzung von optionalen Argumenten und deren erweiterten Form, dem Parameter-Array (Schlüsselwort: ParamArray) zum gleichen Effekt, bleibt aber ein Ersatzmedium, wie wir dies demnächst zeigen werden.

    VB 6.0 kennt das Überladen von Elementen nicht
    Abb. 2: VB 6.0 kennt das Überladen von Elementen nicht

    Die Abb. 2 zeigt das Ergebnis eines Versuches, zwei Methoden mit identischem Namen, aber unterschiedlichen Parametern (unterschiedlichen Datentypen dieser) unter VB 6.0 zu kreieren. Der im Bild dargestellte Ansatz - Verwendung diverser Signaturen für unterschiedliche Parameterkombinationen - entspricht der Definition einer mehrfachüberladenen Methode, z.B. in VB.NET (Abb. 3).

    Der Compiler lehnt unter VB 6.0 die Namenswiederholung im selben Modul (gleichen Gültigkeitsbereich) ab. Nicht die gesamte Signatur der Methode (Name + Parameter) zählt hier, sondern ausschließlich die Bezeichnung der Operation (Delta). Dies führt dazu, dass man für identische Aktionen, wie hier, die Subtraktion, auf Grund ungleicher Datentypen, die als Parameter an der Methode beteiligt sind (in Abb. 2, Integer, Date), unterschiedliche Namen für die Methoden verwenden muss oder aber aufwendige Abwege einbeziehen muss, wie z.B. die Übergabe der Daten über komplexe Datenstrukturen, wie Datensätze (Type unter VB 6.0, Structure unter VB 7.0).

    VB 7.0, d.h. VB.NET (2002) erlaubt nun das vollwertige Überladen (overloads) und weiterhin die nicht ungefährliche Mischform mit dem Parameter-Array, neben der Kreuzung mit dem optionalen Parameter, wie wir zeigen werden.

    Die Abb. 3 demonstriert die Definition und die Verwendung der überladenen Methode Delta unter VB.NET. Beide Methoden tragen die gleiche Bezeichnung, aber unterschiedliche Signaturen (bei gleichen Funktionsnamen, unterschiedliche Datentypen der Parameter). Das optionale Schlüsselwort overloads soll die Lesbarkeit des Codes vereinfachen; deren Verwendung ist nicht zwingend notwendig, obgleich sinnvoll und empfehlenswert.

    Beide Methoden mit der Bezeichnung Delta wurden nun innerhalb gleicher Klasse definiert. Beide verfügen über verschiedenartig typisierte Parameter, daher bei gleichen Namen und unterschiedlichen Datentypen der Parameter letztlich über sich voneinander unterscheidende Signaturen. Wir erinnern uns: Signatur = Name + Parameter (Anzahl + Reihenfolge + Datentypen).

    IntelliSense-unterstütztes Überladen in VB.NET
    Abb. 3: IntelliSenseunterstütztes Überladen in VB.NET

    Von einer Klasse eines (VB.NET-) Formulars aus (Abb. 3) erfolgt nun aus einem Button_Click-Ereignis heraus der Zugriff auf die zweifach überladene Methode Delta, die in einer anderen Klasse definiert wurde. Zuvor muss natürlich ein entsprechender Verweis auf die selbstdefinierte .NET-Assembly (DLL) gesetzt werden, in der sich die Klasse mit der Delta-Methode befindet. Die IntelliSense zeigt nun die beiden Signaturen mit gleichlautenden Namen aber unterschiedlichen Parametertypen an.

    Die Abb. 3 ist eine Montage. Der Zugriffversuch auf die Operation "Delta" erfolgte nacheinander aus dem gleichen Ereignis (Button4_Click) heraus, wobei je eine Signatur (1 of 2 oder 2 of 2) zu sehen war. Das Bild wurde aus Einzelteilen zusammengesetzt um zu einer besseren Übersicht zu verhelfen. Die Schnittlinie deutet die Grenze zwischen den .NET-Klassen an.

    3. Der Problemfall in seinem Kontext

    Die Aufgabe der vorangegangenen Kapitel dieses Dokumentes war eine rasche Einführung in die Thematik des Überladens unter Visual Basic .NET. Befassen wir uns nun mit dem eigentlichen Inhalt dieses Artikels, dem realisierbaren Problemfall unter VB.NET und in diesem Kapitel, mit seinen äußeren Rahmenbedingungen.

    Im Zuge der Arbeit an einem VB.NET-Projekt entstand eine DLL mit der Bezeichnung DeeperHelpers. "Deeper" als Sinnbild in diesem Namen deswegen, weil eine .NET-Assembly (eine DLL) unter dem Namen Helpers bereits existierte. DeeperHelpers beinhaltet dabei diejenigen Aspekte des .NET-Frameworks, die tiefer ("deeper") als die Oberflächenkomponenten (Buttons, ListViews, TreeViews, etc.) eines Formulars angesiedelt sind. "Tiefer" ist hier ein Oberbegriff, ein Synonym für die .NET-Konzepte, wie: Reflection, d.h. die Meta-Daten über die .NET-Assemblies, die Registry und das Dateisystem. Die DLL DeeperHelpers enthält überdies eine selbstdefinierte Klasse ErrorHelper, die ein paar Hilfsmittel in Bezug auf die Fehlerprüfung im Programm anbietet. Diese Hilfsmittel stellen eine individuelle Ergänzung zu den bereits in VB.NET vorhandenen Klassen Trace und Debug, sowie deren Methoden dar.

    In der Klasse ErrorHelper sollte eine vierfach überladene Methode Ready entstehen. Das bedeutet, dass die Methode vier mal unter dem gleichen Namen aber mit unterschiedlichen Parametern (Anzahl, Reihenfolge, Datentypen) definiert werden sollte (zum Vergleich, die Methode Delta in der Abb. 3 ist zweifach überladen). Die Aufgabe von Ready ist die Überprüfung von Eingabeparametern anderer Methoden. Methoden, deren Eingabeparameter überwacht werden sollen, rufen Ready auf und übergeben ihr die eigenen Argumente zum Zwecke der Überprüfung. Damit soll die lästige Parameter-Abfrage im Sinne von:

    if XXX is Nothing Or YYY =String.Empty []

    zentral in einem dafür vorgesehenen Modul, eben der überladenen Methode Ready, abgearbeitet werden.

    Die Parameter von Ready sind entweder Objekte oder Strings - eigentlich sind alle Datentypen in .NET Objekte geworden. Andere Typen der Daten verarbeitet das Programm und somit auch Ready, nicht.

    Je nach Parameterkonstellation, und um diese geht es bei der Signatur einer überladenen Methode, nimmt Ready eine Argumentenliste, den Namen des sie aufzurufenden Moduls samt Klassenbezeichnung und ggf. eine Fehlermeldungszeichenkette entgegen (Beispiele 2 und 3).

    Ready prüft, ob die Eingabeparameter, die sie erhält, geeignet für die Weiterverarbeitung im jeweiligen Modul sind, d.h. ob diese initialisiert vorliegen. Falls nicht, wird über die TraceListener -Klasse des .NET-Frameworks, eine gebührende Fehlermeldung generiert.

    Ready soll aktiv werden, bevor eine Ausnahmebehandlung vom .NET-Framework veranlasst wird und zum größeren Verständnis über die Parameterbelegung (vorhanden/nicht vorhanden) beitragen.

    Die Beispiele 2 und 3 zeigen den knappen Code zweier von vier Operationen. Sie sind bezüglich ihrer Implementierung überschaubar - jedoch nicht unbedingt im Hinblick auf das Verhalten im Zusammenspiel mit dem Überladen von Methoden in VB.NET.

    Die Operation im Beispiel 2 nimmt ein Array an Parametern vom Typ String entgegen. Dieses wird elementenweise auf leere Zeichenketten hin untersucht. Die erste, in diesem Array gefundene, leere Zeichenfolge (If TMP = String.Empty) führt zum Abbruch der For-Each-Schleife in dieser Methode und dem Ergebnis: Return False. Damit wird ausgesagt, dass mindestens eines der im Parameter-Array an die Methode Ready übergebenen Argumente fehlt. Fehlt ein Parameter (Ergebnis: Not Ready), kann keine korrekte Informationsverarbeitung im Modul, das Ready aufruft, erfolgen.

    Beispiel 2:

    Public Overloads Shared Function Ready( _
      ByVal ParamArray PARAMS() As String) As Boolean
     
      Dim TMP As String
      For Each TMP In PARAMS
        If TMP = String.Empty Then Return False
      Next
      Return True
    End Function

    Die zweite Signatur der gleichen Methode (Beispiel 3) nimmt weitere Argumente entgegen (CLASSNAME, METHNAME, MSG) und delegiert diese an die Methode HelperErr, falls das Ergebnis der Überprüfung mit Hilfe der Methode aus Beispiel 2 fehlschlägt (if Not ERG Then…).

    Übersetzen wir das vorliegende Code-Modell in die Umgangssprache, bedeutet die Implementierung aus dem Beispiel 3 folgendes: Wenn der Zustand der Parameter (.Ready(PARAMS)) darauf schließen lässt, dass eine Weiterverarbeitung dieser erfolgen kann, ist die Welt in Ordnung (Ready: Return True). Wenn die Parameter hingegen unvollständig vorliegen, wird der Klassenname und der Methodenname des die Methode Ready aufrufenden Moduls und die ggf. vorhandene Fehlermeldung ausgegeben (Aufruf der Methode HelperErr).

    Beispiel 3:

    Public Overloads Shared Function Ready( _
      ByVal CLASSNAME As String, _
      ByVal METHNAME As String, _
      ByVal MSG As String, _
      ByVal ParamArray PARAMS() As String) As Boolean
     
      Dim ERG As Boolean = DeeperHelpers.ErrorHelper.Ready(PARAMS)
      If Not ERG Then DeeperHelpers.ErrorHelper.HelperErr(CLASSNAME, METHNAME, MSG)
      Return ERG
    End Function

    4. Wenn sich die Datentypenbereiche in den Signaturen überlappen

    Die Überschrift dieses Kapitels ist natürlich provozierend formuliert. Den Fall gibt es in Bezug auf den Datentyp der Parameter in VB.NET nur unter sehr spezifischen Bedingungen.

    Wenn wir unseren Blickwinkel ein wenig verstellen und das Überladen von Elementen aus der Perspektive des Compilers betrachten, handelt es sich aber um das Zusammenfallen von Bereichen eines Datentyps, der in mehreren Signaturen zugleich auftritt.

    Wenn die IntelliSense von .NET zeigt, womit der Compiler nicht einverstanden ist, entdecken wir einen abstrusen Sonderfall, der nun geschildert und vermutlich nirgends dokumentiert wird. Eine Lücke in der Definition des Überladens von Elementen unter VB.NET?

    Die Funktionsweise oder besser ausgedrückt, die implementierte Funktionalität der beiden überladenen Methoden aus Beispiel 2 und Beispiel 3 scheint nun offensichtlich zu sein - könnte man meinen. Im Bedarfsfalle rufe ich die erste Signatur der Methode auf, nach Ermessen, die zweite. An dieser Stelle haben wir aber einen gewichtigen Partner im Softwareentwicklungsspiel übersehen, den Compiler selbst.

    Der Entwurf der überladenen Operation Ready erfolgte von den Definitionen dieser, fort, "bottom up", nach oben (Abb. 4, grüner Pfeil).

    Zunächst entstanden die vier voneinander unabhängigen Signaturen (Bild, unten; erste Stufe der Entwicklung), von denen wir nur zwei betrachten (Bsp. 2 und 3), danach wurden die Aufrufe mit den jeweiligen Parametern der Signaturen besetzt (Bild, Symbol der aufzurufenden Methode, oben; zweite Stufe der Entwicklung). "Bottom up" beschreibt in dem Falle die Perspektive, die mental während der Methodendefinition verwendet wird, die geistige Haltung des Entwicklers.

    Diese Vorgehensweise stellt sich oft als akzeptabel in der Softwareentwicklung heraus, insbesondere bei der Definition von "tools", d.h. der Hilfsmittel oder der Hilfsmittelsammlungen. Sie werden zu einem späteren Zeitpunkt bei einem oder mehreren Projekten gebraucht, wobei der exakte Zeitpunkt der Verwendung eine eher untergeordnete Rolle spielt.

    Nachdem die Hilfsmittel in Form von Hilfsklassen, ihren Methoden und Eigenschaften implementiert worden und fast in "Vergessenheit" geraten sind, erfolgt dann die Definition eines sie aufzurufenden Moduls.

    die verschiedenen Betrachtungsrichtungen beim Überladen von Methoden
    Abb. 4: die verschiedenen Betrachtungsrichtungen beim Überladen von Methoden

    Damit dieser Artikel keinen verwerflichen Schatten auf die Softwareindustrie abwirft, füge ich hinzu, dass es sich bei den Inhalten des vorliegenden Dokumentes primär um meine eigenen Erfahrungen aus dem Bereich der Softwareentwicklung handelt. Mein Ziel ist die Reflexion, die Betrachtung einer bestimmten Situation der Vergangenheit und das Aufzeigen möglicher Denkfehler, die in dieser Sachlage erzielbar sind. Aus diesem Grund möchte ich zunächst den ideologischen Kontext, die Geisteshaltung schildern, die Ursache für die Entstehung des Problems (des Kapitels), bevor wir zum Fall selbst und seiner Lösung vordringen.

    Diese Taktik scheint bei einem vorausschauenden Design der Operationen mit wenigen Ausnahmen zu funktionieren. Eine dieser Ausnahmen ist nun die vorliegende, unscheinbare Methode Ready.

    Wir gehen nun davon aus, dass die Methoden mit den Signaturen vom Beispiel 2 und 3 vorliegen. Zwei weitere Signaturvarianten der gleichen Methode bestehen ebenfalls, sind für die gegenwärtige Betrachtung aber irrelevant. Wir wollen nun die überladene Operation Ready einsetzen (Abb. 5).

    Verwendung der überladenen Methode Ready
    Abb. 5: Verwendung der überladenen Methode Ready

    Die IntelliSense zeigt alle vier Signaturen der Methode zur Auswahl an. Wir entscheiden uns für die dritte Version (3 of 4) dieser (Abb. 5).

    Wir wollen die Parameter der Methode "AssemblyTypeToTreeView" untersuchen, exakter, die String-Variable PATH. Noch genauer ausgedrückt: wir leiten das Argument PATH zur Untersuchung an die Methode Ready weiter. Sollte die Analyse scheitern, so wird eine Fehlerausgabe mit dem Klassennamen "ReflectionHelper" und dem bereits aufgeführten Modulnamen generiert. Es soll keine neue Fehlermeldung erzeugt werden, als die bereits in der Fehlerklasse ErrorHelper definierte, daher wird eine leere Zeichenkette an der Stelle des Parameters MSG geliefert. Die Verwendung eines optionalen Parameters für das, hier leere, Argument MSG ist an dieser Stelle nicht möglich, da wir als letzten Parameter den (optionalen) Parameter-Array nutzen wollen.

    Des Teufels/Compilers Küche. Verbergen von Signaturen überladener Methode

    Nachdem wir den Code-Abschnitt (Abb. 5) mit Argumenten belegt haben, lassen wir die VB.NET-Anweisungen übersetzen und starten das System. Das Programm wird ausgeführt, bedauerlicherweise aber nicht in unseren Sinne!

    Im Code der Abb. 5 wird eine Signatur der Methode Ready sicherlich verankert, aber welche?

    Wir haben uns für den Aufruf der dritten Version (3 of 4) des Methodenkopfes entschieden, damit aber an dieser Stelle Wesentliches außer acht gelassen. Der bedeutsame Partner eines Softwareentwicklers, der Compiler, bleibt derjenige, der die endgültige Aufrufentscheidung vollzieht.

    die Signatur-Wahl des Compilers
    Abb. 6: die Signatur-Wahl des Compilers

    Beim Aufruf einer überladenen Routine wird diejenige ihrer Signaturen selektiert, bei der die Datentypumwandlung der Parameter für den Übersetzer am einfachsten zu vollstrecken ist (Abb. 7).

    In der Realität bedeutet diese auf unseren Fall übertragene Aussage, folgendes:

    Gemäß der Abb. 5 haben wir die dritte von den vier verfügbaren Signaturen unserer Methode Ready ausgesucht. Die Parameter der Operation werden nun belegt mit: CLASSNAME ="ReflectionHelper", METHNAME ="AssemblyTypeToTreeView", MSG ="", PARAMS(0)=PATH.

    Präziser ausgedrückt: wir erwarten mit dieser Belegung, den Aufruf der dritten Signatur der Methode Ready.

    Aufruf einer Signatur, Compiler im Einsatz. Top-down
    Abb. 7: Aufruf einer Signatur, Compiler im Einsatz. Top-down

    Tatsächlich aber, findet der Compiler eine weitere, datentypumwandlungstechnisch simplere Signatur der gleichen Operation (Abb. 6) vor. Er fasst die Informationen, über die zu übergebenden Parameter zusammen: "ReflectionHelper" ist ein String, "AssemblyTypeToTreeView" ist ebenfalls ein String, "" steht für eine leere Zeichenfolge (String) und PATH enthält als eine String-Variable eine analoge Information. Es liegen somit vier String-Parameter vor.

    Die Signatur eins von denkbaren vier (Abb. 6) erwartet eine beliebige Menge an Zeichenkettenfolgen, ein Array von Strings. Auf diesem Wege werden die vier Parameter, die wir übergeben wollen, nicht, wie von uns erwartet, der dritten Signatur der Operation (Abb. 5), sondern der ersten (Abb. 6) überreicht.

    Was nun? Hat die IntelliSense gelogen? Ist sie gar nicht intelligent?

    Der Compiler ordnet den zu übergebenden Argumenten ihre Datentypen zu (Abb. 5). Seine Diagnose: "Variablen vom Typ String liegen vor". Anstatt den Parametern nun die benannten Variablen ("erster Parameter heißt CLASSNAME,…", Abb. 5) zuzuweisen, spart er sich diesen Umweg und ruft direkt die Signatur der Abb. 6 auf.

    Die dritte überladene Form der Methode Ready wird demzufolge niemals aufgerufen!

    Die Methode mit der Signatur 3 von 4 (Abb. 5) ist von Anbeginn ihrer Existenz tot und wird vom Compiler und/oder der IntelliSense nicht bemängelt, weil die Signaturen-Kollision niemals diagnostiziert wird.

    Diese Überlagerung von Signaturendatentypen einer überladenen Methode ist nicht mit dem shadowing in Visual Basic .NET gleichzusetzen. Das Schlüsselwort Shadows in VB.NET weist daraufhin, dass ein Element der abgeleiteten Klasse, absichtlich ein gleichnamiges Element der Basisklasse verbergen soll. Bei unserem Problem handelt es sich um das unabsichtliche, ungewollte Verstecken einer Signatur durch eine andere im Rahmen eines Gültigkeitsbereiches.

    Zombie, die Auferstehung eines Toten oder ein Re-Design

    Die dritte Signatur der Methode Ready (Abb. 5) wird zum Leben erweckt, wenn sie einen Parameter einschließt, dessen Datentyp sie als einmalig, eindeutig in der Signaturenmenge herausstellt. Bei einer überladenen Methode, müssen sich alle Methodenköpfe in ihrer Parameteranzahl, ihren Datentypen und/oder deren Reihenfolge in den Signaturen voneinander unterscheiden. Ein Sonderfall dieser Regelung ergibt sich, wie hier, durch die Verwendung des für eine Menge an Argumenten stehenden Parameter-Array.

    Eine Signatur, die für ein Argument das ParamArray-Schlüsselwort verwendet (Beispiel 4) ist gleichwertig mit einer unendlich langen Liste an Signaturen, die jeweils ein Argument mehr als seine Vorgängersignatur besitzt (Beispiel 5).

    Beispiel 4:

    Public Overloads Shared Function Ready( _
      ByVal ParamArray PARAMS() As String) As Boolean
     
      []
    End Function

    Beispiel 5:

    Public Overloads Shared Function Ready(ByVal PARAM1 As String) As Boolean
     []
    End Function
     
    Public Overloads Shared Function Ready(ByVal PARAM1 As String, _
      ByVal PARAM2 As String) As Boolean
     
      []
    End Function
     
    []
     
    Public Overloads Shared Function Ready(ByVal PARAM1 As String, _
      ByVal PARAM2 As String, _
      ByVal PARAM3 As String, … ,    
      ByVal PARAM99999 As String, … ) As Boolean
     
      []
    End Function

    Eine Ausdehnung dieser Ausnahmeform (Parameter-Array als Parameter) ergibt sich durch die Definition eines Parameter-Arrays vom Typ Object. Der Datentyp Object als Typ der Basisklasse aller denkbaren Klassen, nimmt jede Objektinstanz auf. Eine Parameterliste aller denkbaren Objekttypen entspricht dem Argument: ByVal PARAMS() As Object. Das Argument vertritt alle Signaturen eines überladenen Elementes, weil es alle Parameter anderer Signaturen aufnehmen kann.

    Liegt keine Signatur vor, deren Parameter-Typ (z.B. ByVal NAME As String, Typ String) dem Datentyp des zu übergebenden Parameter entspricht (z.B. "Schmidt", soll übergeben werden, Typ String) wird eine Signatur (falls vorhanden) aufgerufen, die an der gleichen Parameter-Position einen Basisklassentyp des Parametertyps bereitstellt (Abb. 8). Liegt auch hier keine entsprechende Signatur vor, wird aufsteigend in der Vererbungshierarchie der Datentypen gesucht, bis hin zur Basisklasse aller Klassen, der Klasse Object. Im Kap. 5 gehen wir näher auf das Thema ein.

    Vererbungshierarchie der Parametertypen
    Abb. 8: Vererbungshierarchie der Parametertypen

    Zurück zu unserem ursprünglichen Beispiel.

    Die Signatur der Abb. 5 wird, solange sie unverändert bleibt, niemals aktiviert. Sie weist Parametertypen auf, die zugleich als einzelne Argumente vom Parameter-Array (Abb. 6) aufwarten können. Auf diese Weise wird sie vom Compiler übergangen, der stets die einfachere der Datentypumwandlungen vornimmt. Die direkte Zuweisung von vier Parametern der Sorte String einem Parameter-Array (Abb. 6) ist elementarer, als die Zuordnung dieser Parameter den benannten String-Parametern (vgl. Abb. 5) und einem Parameter-Array.

    Die Signatur der Abb. 5 wird erreichbar werden, wenn wir mindestens einen ihrer Parameter durch einen, eines abweichenden Datentyps ersetzen oder einen neuen, gleichermaßen anderen Datentyps, dem Methodenkopf, d.h. der Signatur hinzufügen. Diese Änderung darf konsequenterweise keine neue Kollision mit den bereits existierenden Signaturen der überladenen Methode erzeugen.

    Eine alternative Lösungsmöglichkeit des Problems ergibt sich durch den "Gang in die Tiefe" der Parameter. "Gang in die Tiefe" deswegen, weil ein Parameter auch mit Hilfe eines Datensatzes, der wiederum aus mehreren untergeordneten Argumenten besteht (Abb. 9), abgebildet werden kann. "Alternativ" deshalb, weil ein Datensatz zunächst definiert werden muss, womit auch ein neuer Datentyp eingerichtet wird. Dieser Datentyp wir zu einem der Parameter unserer Signatur, womit auch der im Abschnitt zuvor geforderte abweichende Datentyp des neuen Parameters bestimmt wird.

    Vereinigen von Parametern für den
    Abb. 9: Vereinigen von Parametern für den "Transport" im Rahmen eines neuen Datentyps

    Die Argumente der dritten Signatur der überladenen Methode Ready (Abb. 5) werden nun zu einem zusammengesetzten Parameter (Abb. 9), zu einem Datensatz umgewandelt. Die dritte Signatur selbst wird neu modelliert und auf die Aufnahme des neuen Parameters, eines neuen Datentyps (des Datensatzes), vorbereitet (Abb. 10). Damit ist eine ausreichende Unterscheidung der vier Signaturen der überladenen Methode Ready untereinander gegeben.

    Verwendung der korrigierten Signatur der überladenen Methode Ready
    Abb. 10: Verwendung der korrigierten Signatur der überladenen Methode Ready

    5. Überladen von Elementen in Visual Basic, eine Übersicht

    Auf Basis der vorgerückten Befunde versuchen wir nun eine Übersicht über die Formen des Überladens von Elementen in Visual Basic (primär VB.NET 2002, aber auch VB 6.0 und VBA) zu kreieren (Abb. 11). Die vorliegende Darstellung ist sicherlich optimierbar. Im Vordergrund stand für mich der Wunsch, gewisse Zusammenhänge zu ordnen, zu benennen und visuell fassbar darzubieten, um sie anschließend näher beschreiben zu können.

    Die Perspektive der Darstellung: welche Form des Überladens kann ich wann verwenden und/oder mit welcher anderen verknüpfen? Was wäre dabei zu beachten? (Kein Rezept, sondern ein Denkgerüst.)

    Welches sind die Kriterien, nach denen die Parameter einer Methode oder Eigenschaft errichtet werden? Die vermutlich elementarsten sind: die Anzahl der Parameter, die übergeben werden müssen, die Datentypen dieser Parameter und die Gegebenheit, ob diese über einen Bezeichner (einen Namen) erreichbar sind oder unbenannt, über den Index einer Sammlung zur Verfügung stehen. Vergleiche Kap. 2: Signatur = Name + Parameter (Anzahl + Reihenfolge + Datentypen).

     Parameterverwendung in VB bei überladenen Elementen. © P.A. Landau.
    Abb. 11: Parameterverwendung in VB bei überladenen Elementen. © P.A. Landau.

    Diese Kriterien werden von uns in der Phase der Codierung meist verknüpft verwendet, d.h. sowohl die Anzahl der Parameter, als auch deren Bezeichnung und der Datentyp spielen zugleich eine Rolle. Die Übersicht fasst all die Gesichtspunkte zusammen.

    Damit die Merkmale: "Datentypen" und "Benennung" für uns überhaupt darstellbar und analysierbar sind, betrachten wir grundsätzlich einfache Datentypen (String, Integer), keine zusammengesetzten (Type, Structure, usw.), die wiederum ihrerseits andere Datentypen einschließen.

    Prinzipiell müsste diese Darstellung in zweifacher Ausführung existieren. Einer, für die Betrachtung der Parameter innerhalb einer Signatur und einer weiteren, für die Betrachtung mehrerer Signaturen der überladenen Methode miteinander (siehe, unser Problem vom Kap. 4).

    Die Übersicht (Abb. 11) besteht aus zwei Ebenen (1 und 2, Nummerierung am linken Bildrand). Die erste bezieht sich auf die Benutzung eines einzelnen Schlüsselwortes innerhalb der Signatur (z.B.: Public Function Test(ByVal ParamArray PARAMS() As String)), die zweite, auf eine Kombination der Schlüsselbegriffe im Rahmen einer einzelnen Signatur (z.B.: Public Overloads Function Test(ByVal ParamArray PARAMS() As String)). Der Buchstabe "M" im Viereck symbolisiert hier eine "Mischform". Ein rotes Viereck drückt eine theoretisch denkbare, aber praktisch nicht sinnvolle, bzw. konzeptionell redundante oder riskante Kombination der beiden Schlüsselwörter aus (unser Fall). Ein rotweißes Viereck sagt aus, dass wir an der Stelle einen gedanklichen Sprung in die zweite, nicht existierende Darstellung wagen, um dort nicht die Parameter einer Signatur miteinander vergleichen, sondern mehrere Signaturen einer überladenen Methode untereinander. Im ersten Falle (eine Signatur) bleibt das Ergebnis harmlos (weiß), im anderen Fall (mehrere Signaturen) kann es zu kontroversen Aufruffällen der Methode/Eigenschaft kommen (rot).

    Wie in der Legende der Abb. 11 ausgedrückt, steht "over" für das Schlüsselwort overloads, das derzeit nur in VB 7.0 (VB.NET 2002) verfügbar ist. "Opt" symbolisiert den optionalen Parameter in Visual Basic 7.0, Visual Basic 6.0 und Visual Basic for Applications (VBA), Schlüsselwort: Optional. "Param" deutet den Schüsselbegriff ParamArray an (VB 6.0, VB 7.0, VBA).

    Die Zeichnungen lassen sich somit, gem. der Abb. 12, wie folgt interpretieren: der linke Teil des Bildes (Schlüsselwort: overloads) betrifft Visual Basic .NET, der rechte (Optional, ParamArray) bezieht sich sowohl auf Visual Basic for Applications, als auch auf Visual Basic 6.0. Die Mischvarianten ("M") sind ausschließlich VB.NET vorenthalten.

    Interpretation der Übersicht. VB-Versionen
    Abb. 12: Interpretation der Übersicht. VB-Versionen

    Die Anzahl der Parameter in der Signatur, die Datentypen der Argumente und die Zugriffsvarianten auf die Parameter (by position, by name) werden, wie eingangs erwähnt, i.d.R. kombiniert beim Entwurf einer Signatur verwendet. Damit die Abb. 11 sachlich vollständig wird, müsste daher eine weitere, die dritte, gegenwärtig nicht existierende Abbildungsebene, alle Kombinationen der Stufen 1 und 2 des Bildes enthalten.

    Aus Gründen der Übersichtlichkeit kürzen wir die Darstellung aber ab und zeichnen die dritte Ebene nicht ein. Wir wollen einen Überblick verschaffen und nicht diesen abschaffen.

    Die römischen Ziffern in der Abbildung dienen der Orientierung und der Herstellung des Bezuges zum Textinhalt.

    Überladen von Elementen in VB.NET, ein Syntaxdiagramm für eine Signatur
    Abb. 13: Überladen von Elementen in VB.NET, ein Syntaxdiagramm für eine Signatur

    Wir zerlegen nun die graphische Übersicht der Abb. 11 in einzelne Blöcke und gehen auf diese separat ein.

    Die Schlüsselkonzepte von Visual Basic, Optional und ParamArray sind "mutual exclusive", d.h. sie schließen sich innerhalb einer Signatur gegenseitig aus. Ein Syntaxdiagramm für den Einsatz der Schlüsselwörter innerhalb einer Signatur muss daher, wie in der Abb. 13 dargestellt, konzipiert sein.

    Überladen von Elementen in VB. Aspekt: Anzahl Parameter
    Abb. 14: Überladen von Elementen in VB. Aspekt: Anzahl Parameter

    Das einem Parameter vorangestellte Schlüsselwort Optional steht für höchstens einen oder keinen (0-1) übergebenen Parameter. Somit können zwei optionale Parameter keinen, einen oder höchstens zwei Parameter (0-2) beim Aufruf entgegennehmen. Die maximale Anzahl der Parameter die einem Element (Methode, Eigenschaft) übergeben werden kann, entspricht der Menge der Optional-Schlüsselwörter, die in der Signatur vorkommen. Sie ist begrenzt auf diese Menge (Abb. 14, II.). Ein als Parameter-Array (ParamArray) deklariertes Argument nimmt hingegen eine unbegrenzte Anzahl (0-8) Parameter auf (Abb. 14, III.).

    Die Schlüsselwörter Optional und ParamArray schließen sich unter dem Aspekt der Menge gegenseitig aus, weil eine Signatur entweder eine begrenzte (optional, 0-1) oder eine unbegrenzte (ParamArray, 0-8) Menge an Parametern haben kann. Ein Parameter-Array ist implizit, d.h. stillschweigend optional, weil er auch den Fall abdeckt, in dem kein Parameter übergeben wird, d.h. optional ist. Eine Signatur kann daher Parameter, von der Sorte Optional und ParamArray zugleich nicht enthalten (Beispiel 6).

    Beispiel 6 : (Nicht möglich)

    Public Overloads Function Ready( _
      Optional ByVal CLASSNAME As String, _
      ByVal ParamArray PARAMS()) 

    Sowohl CLASSNAME, als auch PARAMS() wären hier optional. Welchen Fall würde folgender Aufruf betreffen:

  • Ready("Txt") ? => PARAMS(0)="Txt" oder CLASSNAME="Txt" ?
  • Ready("ABC", DEF", "GHI") ? => PARAMS(0)="ABC" oder CLASSNAME="ABC"

    Überladen von Elementen in VB.NET (overloads, Abb. 14, I. und Beispiel 7) entspricht einer Definition für das jeweilige Element, ausgedrückt mit optionalen Parametern (Beispiel 8).

    Die vorliegenden Definitionen (Beispiel 7 gegenüber Beispiel 8, beide VB.NET-Syntax) sind im Hinblick auf das Ergebnis, das sie erzielen, äquivalent.

    Beispiel 7:

    Public Overloads Function User(ByVal NACHNAME As String) As String
        Return NACHNAME
    End Function
     
    Public Overloads Function User(ByVal NACHNAME As String, ByVal VORNAME As String) As String
        Return String.Concat(NACHNAME, Space(1), VORNAME)
    End Function

    Beispiel 8:

    Public Function User(ByVal NACHNAME As String, Optional ByVal VORNAME As String = "") As String
        Return String.Concat(NACHNAME, Space(1), IIf(VORNAME <> "", VORNAME, String.Empty))
    End Function

    Das Beispiel 9 zeigt eine zum Beispiel 8 analoge Definition in der VB 6.0 und VBA-Syntax.

    Beispiel 9:

    Public Function User(ByVal NACHNAME As String, Optional ByVal VORNAME As String = "") As String
        User = NACHNAME + IIf(VORNAME <> "", Space(1) + VORNAME, "")
    End Function ' Alternativdefinition in der VB 6.0- und VBA-Syntax:

    Ein Überladen von Elementen mit Hilfe von optionalen Parametern in Visual Basic stellt ein Ersatzkonstrukt, eine Alternative zum Überladen im Sinne vom Beispiel 7 (overloads) dar. Die Ausdrucksformen sind ähnlich, aber nicht gleich. Dies wird deutlich, wenn wir eine weitere Signatur der überladenen Methode aus Beispiel 7 hinzufügen:

    Beispiel 10: ergänzt das Beispiel 7 um eine weitere Signatur

    Public Overloads Function User(ByVal ALTER As Short) As String
        Return ALTER.ToString
    End Function

    Um nun eine Signatur zu erhalten, die mittels optionaler Parameter ausdrückt, was die inzwischen dreifach überladene Methode (Beispiel 7 und Beispiel 10) äußert, wird der Code vom Beispiel 8 aktualisiert. Der neue, optionale Parameter ALTER ergänzt nun die Parameterfolge der Funktion User:

    Beispiel 11:

    Public Function User(Optional ByVal NACHNAME As String = "", 
      Optional ByVal VORNAME As String = "", _ 
      Optional ByVal ALTER As Short = 0) As String
     
      Return String.Concat(NACHNAME, Space(1), _
        IIf(VORNAME <> "", VORNAME, String.Empty), Space(1), ALTER.ToString)
    End Function

    Ein Aufruf der Routine erfolgt gem. den Regeln aus dem Kap. 1.2:

    Beispiel 12:

    User(ALTER:=CShort(26))

    Nun entspricht der Aufruf einer mittels optionalen Parametern überladener Methode User (Beispiel 12), sinngemäß der mittels overloads überladener aus Beispiel 10 : User(26).

    Damit die Aufrufform aus Beispiel 12 realisierbar ist, müssen alle zuvor definierten Parameter der Methode, optional vorliegen (Beispiel 11). Bei drei optionalen Parametern, mit je zwei vorstellbaren Zuständen (Parameter vorhanden / Parameter nicht vorhanden), ergeben sich 2x2x2, d.h. 8 Belegungskombinationen der Signatur mit Argumenten. Auf diese Weise entstehen Einsetzungsvarianten, die nicht beabsichtigt sind, wie die Kombination aus VORNAME und ALTER und NACHNAME und ALTER (Abb. 15, vgl. mit Beispiel 7 und Beispiel 10).

    Überladen mit optionalen Parametern
    Abb. 15: Überladen mit optionalen Parametern

    Im Beispiel 7 sind nur vier Varianten der Parameterbelegung enthalten (2 Parameter, je 2 Zustände), im Beispiel 10, weitere 2. Dies hat 4+2=6 denkbare Zustände zur Folge, d.h. um zwei weniger, als bei der mit optionalen Parametern überladener Methode (Abb. 11, Abb. 15).

    Es lässt sich mutmaßen, dass bei steigender Anzahl an Argumenten in einer Signatur, die Menge unzulässiger Parametereinsetzungen zunimmt, wenn ein Element mit Hilfe optionaler Parameter überladen wird. Natürlich im Vergleich zu einem mittels overloads überladenen Element.

    Zurück zur Übersichtsbesprechung und der Abb. 14.

    Eine Komposition (Abb. 14, XIII.) aus den Schlüsselbegriffen overloads und optional lässt der .NET-Compiler zu, auf diese Art und Weise werden aber inkonsequent zwei Ausdrucksformen für ein Konzept miteinander gekreuzt. Konsequenterweise erfolgt das Überladen in anderen Programmiersprachen, wie z.B. C++, so, wie dies mittels overloads in VB.NET geschieht.

    Die Verwendung des Schlüsselwortes overloads ist optional. Der Compiler erkennt die Absicht des Überladens an den voneinander abweichenden Signaturen der Elemente. Es dürfen entweder die Eigenschaften oder die Methoden einer Klasse untereinander überladen werden. Eine Zusammensetzung aus einer Methode und einer Eigenschaft mit identischem Namen und abweichenden Parametern wird nicht zugelassen.

    Die Mischform XIV. der Abb. 14 macht Sinn. Ein Parameter-Array mit unbegrenzter Argumentenmenge (0-8) erweitert ein überladenes Element mit seiner begrenzten Anzahl an Parametern. Die Funktion aus Beispiel 3 zeigt eine solche Kombination. Darin stehen CLASSNAME, METHNAME und MSG für eine fixe Menge an Parametern, wohingegen das Parameter-Array PARAMS(), eine Ausdehnung der Signatur vornimmt und weitere, beliebig viele Parametereinsetzungen erlaubt

    Überladen von Elementen in VB. Aspekt: Datentyp eines Parameters
    Abb. 16: Überladen von Elementen in VB. Aspekt: Datentyp eines Parameters

    Unter dem Aspekt des Datentyps der Parameter kann die Signatur eines Elementes (einer Methode oder einer Eigenschaft) entweder alle Argumente gleichen Datentyps oder Argumente unterschiedlichen Typs aufnehmen. Die Übersicht der Abb. 16 bietet zunächst kaum Informationszugewinn.

    Ein Überladen von Elementen erfolgt im Rahmen einer Signatur mit dem optionalen Parameter (Abb. 16, V.) oder mit Hilfe des Parameter-Arrays (VI.). Sachkundig und/oder abhängig von der verwendeten Visual Basic-Version mit Zuhilfenahme des Schlüsselwortes: overloads (IV.). Die Kombination XV. drückt einen Sachverhalt ("ich möchte überladen") redundant mit zwei verschiedenen Ausdrucksmitteln (overloads, optional) aus. Die Komposition XVI. erweitert die zu überladende Signatur um eine unendliche Menge an Datentypen (ParamArray) und stellt die Extremvariante der Mischform XVIII. dar. Sofern wir nur eine einzelne Signatur für sich betrachten, die das Schlüsselwort overloads benutzt und deren letzter Parameter mit dem Schlüsselwort ParamArray deklariert wird, erfahren wir zunächst eine Ergänzung der Signatur. Ein Parameter-Array erlaubt beliebig viele Argumente an der letzten Stelle der Signatur aufzunehmen. Betrachten wir aber mehrere überladene Signaturen im Zusammenspiel miteinander, kann die Realität im Programmiereralltag ein wenig verwickelt ausfallen, wie die folgenden Beispiele belegen:

    Beispiel 13:

     
    Public Overloads Sub Test(ByVal ParamArray PARAMS() As Object)
     
    End Sub
     
    Public Overloads Sub Test(ByVal DI As System.IO.DirectoryInfo)
     
    End Sub

    Das Beispiel 13 stellt zwei Methodenköpfe der überladenen Methode Test dar, Beispiel 14 demonstriert den zugehörigen Aufruf der überladenen Methode.

    Beispiel 14:

    Dim TMP As System.IO.DirectoryInfo()
    TST.Test(TMP)

    Es drängt sich die Frage auf, welche der beiden Signaturen aus Beispiel 13 nun aufgerufen wird, wenn das System aktiviert wird? Tatsächlich die, mit dem Parameter-Array. Die Klammerangabe am Ende des Datentyps System.IO.DirectoryInfo() führt dazu, dass mit der Variablen TMP ein deklariertes Array vorliegt, auch wenn mit keinem einzigen Objekt belegt (Nothing). Ein Array an Parametern (erste Signatur aus Beispiel 13) nimmt ein leeres Array (TMP) entgegen. Wird die Klammer in der Deklaration hinter DirectoryInfo entfernt, liegt eine einfache Variable vor. Bei gleichem Code wird nun die zweite Signatur (mit dem Parameter DI) verwendet.

    Die Verwirrung lässt sich mit dem nächsten Beispiel noch ein wenig steigern.

    Beispiel 15:

    Public Overloads Sub Test(ByVal ParamArray FSI() As System.IO.FileSystemInfo)
     
    End Sub
     
    Public Overloads Sub Test(ByVal DI As System.IO.DirectoryInfo)
     
    End Sub

    Wir verwenden jetzt die Aufrufform vom Beispiel 14, mit welchem Ergebnis? Welche Signatur der überladenen Methode Test (Beispiel 15) wird nun aufgerufen?

    Ein leeres Array (TMP) vom Typ System.IO.DirectoryInfo kann von einem Parameter-Array der Sorte System.IO.FileSystemInfo (Beispiel 15, Signatur 1) empfangen werden, weil FileSystemInfo die Basisklasse für DirectoryInfo darstellt (vgl. Abb. 8). Entfernen wir die Array-Klammern, wird die zweite Signatur vom Beispiel 15 aktiviert.

    Und noch ein Beispiel.

    Beispiel 16:

    Public Overloads Sub Test( _
      ByVal ParamArray FSI() As System.IO.FileSystemInfo) ' FSInfo: Basisklasse
     
    End Sub
     
    ' DirectoryInfo und FileInfo sind die von FileSystemInfo 
    ' abgeleiteten Klassen (.NET Framework)
    Public Overloads Sub Test(ByRef DI As System.IO.DirectoryInfo, _
      ByRef FI As System.IO.FileInfo)
     
    End Sub

    Hierzu verwenden wir den folgenden Aufruf:

    Beispiel 17:

    Option Explicit Off
    Option Strict Off
     
    Dim DI As New System.IO.DirectoryInfo("D:")
    Dim FI As New System.IO.FileInfo("D:\Test.txt")
    Dim FSI As System.IO.FileSystemInfo
     
    FSI = DI
    TST.Test(FSI, FI)

    Der Datentyp der Variablen FSI (Beispiel 17) ist vom Typ der Basisklasse der beiden Klassen DirectoryInfo (Variable DI) und FileInfo (Variable FI). Zur Laufzeit des Systems wird die Basisklassenvariable FSI mit der Instanz ihrer abgeleiteten Klasse DI belegt (FSI = DI). Mit dem Aufruf TST.Test(FSI, FI) erfolgt die Übergabe einer Instanz von DirectoryInfo über die Variable FSI an die überladene Methode Test.

    Obwohl das Argument FI (Beispiel 17) in diesem Aufruf, mit dem zweiten Parameterdatentyp der ebenfalls zweiten Signatur aus Beispiel 16 übereinstimmt, wird nicht die zweite, sondern die erste Signatur der überladenen Methode aktiv.

    Im Beispiel 15 (beim Aufruf) stand nicht der Datentyp selbst, sondern seine Struktur, die Beschaffenheit im Vordergrund (Array). Im Beispiel 16 hingegen war die Bindung an den statischen Datentyp (System.IO.FileSystemInfo) ausschlaggebend.

    Die Variable FSI (Beispiel 17) vom Typ System.IO.FileSystemInfo hat den Aufruf der ersten Signatur der Methode Test aus Beispiel 16 herbeigeführt, obwohl sie zur Laufzeit, mit einer Instanz ihrer abgeleiteten Klasse aufgerufen worden war (DI, System.IO.DirectoryInfo, Beispiel 17). Wäre es nicht denkbar gewesen, dass hier der Datentyp des Parameters, der in der Variablen FSI enthalten ist, den Aufruf der zweiten Signatur aus Beispiel 16 verursacht?

    Kommen wir nun zurück zur Abb. 16.

    Besitzen alle Parameter eines Elementes den gleichen Datentyp, ist es unerheblich, ob das Element mit Hilfe von optionalen Parametern überladen wird (Abb. 16, VIII.) oder professioneller, mit Hilfe des Schlüsselwortes overloads in VB.NET (Abb. 16, VII.). Die Fälle VIII. und IX. schließen sich gegenseitig (wg. "mutual exclusive") aus, Fall XVII. stellt, wie zuvor, die Mischung zweier alternativer Formen gleichen Konzepts dar.

    Die Situation, die entsteht durch die Verknüpfung des ParamArray-Schlüsselwortes (IX.) mit dem Konzept des Überladens von Elementen in VB.NET (overloads, VII.) bei gleichen Datentypen (Abb. 16, XVIII.) stellt unseren Problemfall aus dem Kap. 4 dar, wenn wir nicht eine, sondern mehrere Signaturen mit diesen Merkmalen (ParamArray, overloads) miteinander vergleichen.

    Überladen von Elementen in VB. Aspekt: Parameterzugriff
    Abb. 17: Überladen von Elementen in VB. Aspekt: Parameterzugriff

    Unter dem Aspekt des Datenzugriffs auf den Parameter eines zu überladenden Elementes, können die bereits im Kap. 1.2 aufgeführten Varianten (Abb. 17) unterschieden werden: namentlich "by name", sowie positionsbedingt, "by position", d.h. erreichbar über den Index eines Parameter-Array.

    Die Benennung der einzelnen Parameter einer überladenen Methode (ByVal NAME1 As …, ByRef NAME2 As…) liegt bei einfachen Datentypen (String, Integer) immer vor. Aus diesem Grund ist es unerheblich, mit welchem Mittel die Überladung eines Elementes erfolgt (mit Hilfe von overloads, Abb. 17, Variante X. oder mit dem optionalen Parameter, Variante XI.). Unter dem Gesichtspunkt der Namensgebung von Parametern sind bei einfachen Datentypen X. und XI. gleichwertig. Eine Mischung (XIX.) beider Alternativen des Überladens macht auch hier wenig Sinn.

    Spielt die Bezeichnung einzelner Parameter eine untergeordnete Rolle, bzw. können die Parameter auf Grund ihrer Menge nicht befriedigend benannt werden, bietet sich das Überladen der Methode mit Hilfe eines Parameter-Array (XII.) an. Zusätzlich kann auch das Schlüsselwort overloads (Variante XX.) hinzugezogen werden.

    6. Eigenschaft als Sonderform der Methode

    Eine Eigenschaft (Property) ist eine Sonderform der Methode. Anders ausgedrückt, eine vollständige VB.NET-Property besteht aus zwei einzelnen Methoden, der get-Methode und der set-Methode.

    Beispiel 18:

    Public Property Icon() As Byte
       Get
          Return Me.m_ICON
       End Get
     
       Set(ByVal Value As Byte)
          Me.m_ICON = Value
       End Set
    End Property

    Die einfache Eigenschaft Icon aus dem Beispiel 18 wird vom Compiler, wie in der Abb. 18 gezeigt, abgebildet. Der Namensraum System.Reflection enthält Mittel, mit welchen die Metadaten einer .NET-Assembly (DLL) inspiziert werden können. Aus dieser Grafik wird ersichtlich, dass die Eigenschaft Icon intern in zwei separate Methoden zerlegt wird. Daraus folgt, dass das Überladen von Eigenschaften unter VB.NET letztlich das Überladen von Methoden unter .NET darstellt.

    Eine VB.NET-Property und ihre .NET-Entsprechung. Ein Blick auf Meta-Daten
    Abb. 18: Eine VB.NET-Property und ihre .NET-Entsprechung. Ein Blick auf Meta-Daten

    7. Fazit und weiterführende Hinweise

    Im vorliegenden Artikel haben wir das Thema des Überladens von Elementen unter Visual Basic (.NET) in einem breiten Rahmen angerissen, aber nicht vollständig behandelt.

    Diejenigen Informationen, die nicht in einem direkten Bezug zum Artikelinhalt standen, habe ich bewusst ausgelassen. Beispiel hierzu ist die "typenlose Programmierung als Alternative zum Überladen" von Elementen. Siehe hierzu die unter Kap. 8 aufgeführten Informationsquellen von Microsoft, insbesondere die aktuelle Microsoft Visual Studio .NET Documentation.

    Die Übersicht der Abb. 11 ist sicherlich zum großen Teil redundant. Mit ihr wollte ich eine denkbare Einordnung der Fälle des Überladens unter Visual Basic (.NET 2002) vornehmen. Sie soll, bei Bedarf, ein individuell ergänzbares Hilfsmittel werden.

    Es ist Vorsicht bei der Verwendung des Parameter-Arrays bei überladenen Methoden geboten. Mit diesem Artikel wollte ich die Wachsamkeit auf Probleme in diesem Zusammenhang erhöhen und ein Beispiel dafür liefern (Kap. 4), wie man nicht unbedingt vorgehen sollte. Kurz: die Signaturen überladener Methoden sollten - vor der Aufruf-Erstellung - einander gegenübergestellt werden, da weder der Compiler, noch die IntelliSense, intelligent genug sind, um Fehler in diesem Sektor auszukundschaften.

    Anregungen, Kritik, Verbesserungsvorschläge nehme ich gerne entgegen:  landxgmx.net

    8. Quellen

    • HGD2000
      Handbuch der praktischen und technischen Informatik
      Hering / Gutekunst / Dyllong
      Springer, 2000, ISBN 3-540-67626-0.
       
    • MSDN Library Visual Studio 6.0. (VB 6.0)
    • Microsoft Visual Studio .NET Documentation. (VB.NET)
    • Microsoft Visual Basic Help. (MS Office 2000)


    [1] IntelliSense: Zugriff auf Informationen über den Code. Metadaten.
    [2] Element in VB: Function, Sub, Property.
    [3] Ein Gültigkeitsbereich: hier, eine Klasse.
    [4] System.TimeSpan ist ein .NET-Datentyp und somit nicht verfügbar unter VB 6.0 und VBA.
    [5] Unter VB 6.0 und VBA muss ein Parameter-Array als ein Array vom Typ Variant deklariert werden.
    [6] TraceListener Class: base class for the listeners who monitor trace and debug output.
    [7] Statischer Datentyp als Gegenbegriff zum dynamischen Datentyp, den Datentyp einer Instanz zur Laufzeit des Systems.
    [8] Ausgenommen ReadOnly-, WriteOnly-Properties, die nur get- bzw. die set-Methode enthalten.



  • Anzeige

    Kauftipp
    Unser Dauerbrenner!Diesen und auch alle anderen Workshops finden Sie auch auf unserer aktuellen vb@rchiv  Vol.6

    Ein absolutes Muss - Geballtes Wissen aus mehr als 8 Jahren vb@rchiv!
    - nahezu alle Tipps & Tricks und Workshops mit Beispielprojekten
    - Symbol-Galerie mit mehr als 3.200 Icons im modernen Look
    Weitere Infos - 4 Entwickler-Vollversionen (u.a. sevFTP für .NET), Online-Update-Funktion u.v.m.
     
     
    Copyright ©2000-2024 vb@rchiv Dieter OtterAlle Rechte vorbehalten.


    Microsoft, Windows und Visual Basic sind entweder eingetragene Marken oder Marken der Microsoft Corporation in den USA und/oder anderen Ländern. Weitere auf dieser Homepage aufgeführten Produkt- und Firmennamen können geschützte Marken ihrer jeweiligen Inhaber sein.