Rubrik: Variablen/Strings · Array/ArrayList | VB-Versionen: VB.NET | 14.05.07 |
Flexible Array-Übergabe an Funktionen (VB 2005) Unterschiedlich deklarierte Arrays als OBJECT-Parameter an eine Funktion übergeben | ||
Autor: Manfred Bohn | Bewertung: | Views: 18.782 |
ohne Homepage | System: WinNT, Win2k, WinXP, Win7, Win8, Win10, Win11 | kein Beispielprojekt |
Manchmal möchte man Funktionen erstellen, die als Parameter übergebene Arrays verarbeiten, die unterschiedliche Datentypen und/oder eine unterschiedliche Zahl von Dimensionen aufweisen können. (Man beachte den Unterschied zwischen mehrdimensionalen und 'verzweigten' Arrays = Arrays, die Arrays als Felder enthalten. Die sind mit der CLS nicht kompatibel !!)
Zu denken ist z.B. an Routinen, die Berechnungen mit Gleitkomma-Werten durchführen, wobei es egal sein soll, ob die Daten in einem Single-, Double- oder Decimal-Array vorliegen.
Auch die Array-Dimensionen können bei manchen Anwendungen variieren. Daten könnten in einem Programm an einer Stelle zweckmäßig als Vektoren ( = eindimensionale Arrays), woanders als Matrix ( = zweidimensionales Array) oder als Kubus ( = dreidimensionales Array) organisiert sein.
Funktionen können durch die Verwendung von OBJECT bei der Parameter-Übergabe eines Array entsprechend flexibel gestaltet werden. In diesem Fall wird erst zur Laufzeit des Programms festgelegt, welche Art von Objekt an die Funktion als Parameter übergeben wird (späte Bindung).
Die Verwendung des OBJECT-Parameters hat einige Auswirkungen:
- Die OPTION STRICT ON - Anweisung darf in dem Modul nicht enthalten sein, das Funktionen mit OBJECT-Parametern enthält, weil sie Zugriffe auf die spezifischen Methoden und Eigenschaften von als OBJECT übergebenen Objekten nicht duldet. (Aber: OPTION EXPLICIT ON kann verwendet werden)
- Die IntelliSense der VB-Entwicklungsumgebung funktioniert bei OBJECT-Parametern nur eingeschränkt. Angezeigt werden nur die allgemeinen OBJECT-Eigenschaften und Methoden.
- Die 'späte Bindung' erlaubt keine Typ-Überprüfung beim Kompilieren (die sog. 'lose Typisierung') und sie beansprucht mehr Rechenzeit bei der Code-Ausführung.
- Die Funktionen sollten vor der Verwendung von Methoden und Eigenschaften der OBJECT-Parameter zunächst explizit prüfen, ob überhaupt ein Objekt und ob eine Instanz des erwarteten Objekts (d.h. in unserem Fall: ein Array) übergeben worden ist.
Dazu die VB-Doku:
Die späte Bindung erfordert zusätzliche Ausführungszeit. Außerdem wird der Code auf die Methoden und Eigenschaften der Klasse beschränkt, die Sie zuletzt zugewiesen haben. Wenn der Code auf Member einer anderen Klasse zuzugreifen versucht, kann es dadurch zu Laufzeitfehlern kommen.
Weitere Hinweise:
Es ist möglich, die Zahl der Dimensionen und die Obergrenze der Dimensionen eines als OBJECT übergebenen Array in der gerufenen Funktion (lokal) zu ändern (REDIM-Anweisung) - falls das Array aber BYREF übergeben worden ist, entsteht bei der Rückgabe gewöhnlich ein Fehler.
Der Datentyp des als OBJECT übergebenen Array kann in der gerufenen Funktion nicht explizit geändert werden, weil keine DIM-Anweisung für Parameter zulässig ist.
VB-Doku: Traversieren von Arrays (For Each ... Next).
Da die Array-Klasse die IEnumerable-Schnittstelle implementiert, machen alle Arrays die GetEnumerator-Methode verfügbar. Das bedeutet, dass Sie ein Array mit einer 'For Each ...Next'Schleife traversieren können. Allerdings können Sie die Arrayelemente NUR LESEN, nicht ändern. .... Die Traversalreihenfolge wird dabei nicht durch Visual Basic festgelegt, sondern von der MoveNext-Methode des Enumerationsobjekts. .... Das von 'GetEnumerator' zurückgegebene Enumerationsobjekt ermöglicht es Ihnen NICHT, die Auflistung durch Hinzufügen, Löschen, Ersetzen oder Neuordnen von Elementen ZU ÄNDERN (Hervorhebungen - der Verf.)
Bei mehrdimensionalen Arrays ergibt sich die Reihenfolge der durch die interne MoveNext-Methode traversierten Elemente durch Hochsetzen des Index der letzten (höchsten) Dimension usw.
Beispiel (Funktion 'Array_Info'):
Die als Bespiel beigefügte Funktion 'Array_Info' akzeptiert im OBJECT-Parameter 'ARR' ein Array aus einem der Gleitkomma-Datentypen, das beliebig viele Dimensionen umfassen kann.
Bei Übergabe eines ungeeigneten Objekts wird eine entsprechende Meldung und 'false' zurückgeliefert.
Die optionalen Parameter informieren über den Datentyp des Array, die Gesamtzahl der Array-Felder, die Anzahl der Array-Dimensionen, die kleinste und die größte Ausprägung eines Arrayfeld-Wertes.
Liegen in einem oder mehreren Feldern die Ausprägungen 'PositiveInfinity' oder 'NegativeInfinity' vor
(nur bei SINGLE, DOUBLE möglich), enthalten die Parameter MINIMUM bzw. MAXIMUM diese IEEE-Sonderwerte.
Die Anzahl der Array-Felder, die positive (>0) bzw. negative Werte aufweisen, wird ermittelt und - optional - zurückgegeben. Felder, die Infinity-Werte enthalten, werden jeweils mitgezählt.
Der optionale Parameter SUMME enthält die Summe der Ausprägungen aller Array-Felder.
Sollte bei der Summation die zulässige numerische Ausprägung des Datentyps DOUBLE über- oder unterschritten werden, steht in SUMME der IEEE-Sonderwert 'NaN' ('not a number').
Man beachte, dass die Parameter MINIMUM, MAXIMUM, SUMME vom Typ Double sind - also nicht als OBJECT übergeben werden - , und unabhängig vom Datentyp des übergebenen Array Double-Werte zurückgeben.
Sollte in mindestens einem Array-Feld des Parameters 'ARR' ein 'NaN'-Wert ermittelt werden (nur möglich bei SINGLE, DOUBLE) , wird von der Funktion 'ARRAY_INFO' ein auffangbarer Fehler ausgelöst. Zu diesem Zweck habe die 'SYSTEM.Overflowexception' herangezogen.
Public Function Array_Info(ByVal arr As Object, _ Optional ByRef DatenTyp As String = "", _ Optional ByRef Anzahl_Felder As Long = 0, _ Optional ByRef Anzahl_Dimensionen As Short = 0, _ Optional ByRef Minimum As Double = 0, _ Optional ByRef Maximum As Double = 0, _ Optional ByRef Negative_Felder As Integer = 0, _ Optional ByRef Positive_Felder As Integer = 0, _ Optional ByRef Summe As Double = 0, _ Optional ByRef Meldung As String = "") _ As Boolean ' Verarbeitete Daten-Typen (Gleitkomma-Variable) Dim st_double As String = "SYSTEM.DOUBLE" Dim st_single As String = "SYSTEM.SINGLE" Dim st_decimal As String = "SYSTEM.DECIMAL" Dim dbl As Double ' intern: einheitlicher Datentyp Dim pos As Integer ' Stringanalyse ' Rückgabe zunächst explizit auf 'undefiniert' setzen DatenTyp = "" Anzahl_Felder = -1 Anzahl_Dimensionen = -1 Minimum = Double.NaN Maximum = Double.NaN Positive_Felder = -1 Negative_Felder = -1 Summe = Double.NaN Meldung = "" ' Ist in 'arr' ein Objekt gegeben worden? Try If arr = Nothing Then Meldung = "Kein Objekt verfügbar" Return False End If Catch ' muss abgefangen werden ' weil der nothing-Vergleich bei ' dekl. Array Fehler auslöst End Try ' Kennung für den Typ des übergebenen Objekts ermitteln Dim at As String = UCase(arr.GetType.ToString) ' Liegt in 'arr' ein Array vor , d.h. steht [] im Type}? pos = InStr(at, "[") If pos = 0 Then Meldung = "Das Objekt ist kein Array" Return False End If ' Datentyp des Array ermitteln DatenTyp = Left(at, pos - 1) ' Wird der Datentyp von 'arr' akzeptiert? If InStr(at, st_double) = 0 And _ InStr(at, st_single) = 0 And _ InStr(at, st_decimal) = 0 Then Meldung = "Der Datentyp wird nicht unterstützt" Return False End If ' Zahl der Array-Dimensionen abfragen Anzahl_Dimensionen = arr.Rank ' Zahl der Array-Felder abfragen Anzahl_Felder = arr.LongLength ' Kennwerte des Array-Inhaltes ermitteln ' Initialisierung der Rückgabe-Variablen Minimum = Double.PositiveInfinity Maximum = Double.NegativeInfinity Positive_Felder = 0 Negative_Felder = 0 Summe = 0 ' Hier wird das Array-Objekt 'arr' als Auflistung betrachtet ' und es werden sukzessive alle Felder abgefragt ' (nur Lesezugriff ist möglich!) For Each field As System.Object In arr ' Inhalt des aktuellen Feldes in Double-Wert wandeln dbl = CDbl(field) If Double.IsNaN(dbl) Then ' nicht-numerischer Wert in einem Feld --> ' Funktion löst auffangbaren Fehler aus Throw New System.OverflowException Exit Function End If ' größten und kleinsten Wert im Array ermitteln ' ggf. werden Infinity-Werte ermittelt If dbl > Maximum Then Maximum = dbl If dbl < Minimum Then Minimum = dbl ' Anzahl der Felder, die positive bzw. ' negative Werte enthalten If dbl < 0 Then Negative_Felder += 1 ElseIf dbl > 0 Then Positive_Felder += 1 End If ' Summe der Array-Elemente ermitteln ' bei DOUBLE-Überlauf während der Summation: ' ---> Rückgabe des IEEE-Sonderwerts 'NaN' Try If Not Double.IsNaN(Summe) Then ' Summation der Werte der Array-Elemente Summe += dbl ' Überlauf der Summation? ' --> Infinity-Wert entsteht in 'Summe' If Summe > Double.MaxValue Or _ Summe < Double.MinValue Then Summe = Double.NaN End If End If Catch ' nur zur Sicherheit Summe = Double.NaN End Try ' Schleife: nächstes Arrayelement Next field ' alles ín Ordnung --> true Return True End Function