Problembehandlung bei Prozeduren (Visual Basic)

Auf dieser Seite werden einige allgemeine Probleme aufgelistet, die beim Arbeiten mit Prozeduren auftreten können.

Zurückgeben eines Arraytyps über eine Funktionsprozedur

Wenn eine Function-Prozedur einen Arraydatentyp zurückgibt, können Sie den Function-Namen nicht verwenden, um Werte in den Elementen des Arrays zu speichern. Wenn Sie versuchen, diesen Vorgang durchzuführen, interpretiert der Compiler dies als Aufruf von Function. Im folgenden Beispiel werden Compilerfehler generiert:

Function AllOnes(n As Integer) As Integer()
   For i As Integer = 1 To n - 1  
      ' The following statement generates a COMPILER ERROR.  
      AllOnes(i) = 1  
   Next  

   ' The following statement generates a COMPILER ERROR.  
   Return AllOnes()  
End Function

Die Anweisung AllOnes(i) = 1 generiert einen Compilerfehler, da AllOnes mit einem Argument des falschen Datentyps aufgerufen wird (skalarer Integer anstelle eines Integer-Arrays). Die Anweisung Return AllOnes() generiert einen Compilerfehler, da AllOnes ohne Argument aufgerufen wird.

Richtiger Ansatz: Um die Elemente eines Arrays zu ändern, das zurückgegeben werden soll, definieren Sie ein internes Array als lokale Variable. Im folgenden Beispiel wird ohne Fehler kompiliert:

Function AllOnes(n As Integer) As Integer()
    Dim iArray(n - 1) As Integer
    For i = 0 To n - 1
        iArray(i) = 1
    Next
    Return iArray
End Function

Argument nicht durch Prozeduraufruf geändert

Wenn Sie einer Prozedur erlauben möchten, ein Programmierelement zu ändern, das einem Argument im aufrufenden Code zugrunde liegt, müssen Sie es durch Verweis (ByRef) übergeben. Eine Prozedur kann jedoch auch dann auf die Elemente eines Verweistyparguments zugreifen, wenn Sie es nach Wert (ByVal) übergeben.

  • Zugrunde liegende Variable: Damit die Prozedur den Wert des zugrunde liegenden Variablenelements selbst ersetzen kann, muss die Prozedur den Parameter durch Verweis (ByRef) deklarieren. Außerdem darf der aufrufende Code das Argument nicht in Klammern einschließen, da dadurch der ByRef-Übergabemechanismus überschrieben werden würde.

  • Verweistypelemente: Wenn Sie einen Parameter nach Wert (ByVal) deklarieren, kann die Prozedur das zugrunde liegende Variablenelement nicht selbst ändern. Wenn das Argument jedoch ein Verweistyp ist, kann die Prozedur die Member des Objekts ändern, auf das sie verweist, auch wenn sie den Wert der Variablen nicht ersetzen kann. Wenn es sich bei dem Argument beispielsweise um eine Arrayvariable handelt, kann die Prozedur ihm kein neues Array zuweisen, aber sie kann ein oder mehrere Elemente ändern. Die geänderten Elemente werden in der zugrunde liegenden Arrayvariablen im aufrufenden Code wiedergegeben.

Im folgenden Beispiel werden zwei Prozeduren definiert, die eine Arrayvariable nach Wert verwenden und die Elemente bearbeiten. Die Prozedur increase fügt jedem Element einfach ein Array hinzu. Die Prozedur replace weist dem Parameter a() ein neues Array zu und fügt dann jedem Element ein Array hinzu. Die Neuzuweisung wirkt sich jedoch nicht auf die zugrunde liegende Arrayvariable im aufrufenden Code aus, da a() nach Wert (ByVal) deklariert wird.

Public Sub increase(ByVal a() As Long)
    For j As Integer = 0 To UBound(a)
        a(j) = a(j) + 1
    Next j
End Sub
Public Sub replace(ByVal a() As Long)
    Dim k() As Long = {100, 200, 300}
    a = k
    For j As Integer = 0 To UBound(a)
        a(j) = a(j) + 1
    Next j
End Sub

Im folgenden Beispiel werden increase und replace aufgerufen:

Dim n() As Long = {10, 20, 30, 40}
Call increase(n)
MsgBox("After increase(n): " & CStr(n(0)) & ", " & 
    CStr(n(1)) & ", " & CStr(n(2)) & ", " & CStr(n(3)))
Call replace(n)
MsgBox("After replace(n): " & CStr(n(0)) & ", " & 
    CStr(n(1)) & ", " & CStr(n(2)) & ", " & CStr(n(3)))

Der erste MsgBox-Aufruf zeigt „After increase(n): 11, 21, 31, 41“ an. Da es sich bei n um einen Verweistyp handelt, kann increase die Member auch bei der Übergabe nach Wert (ByVal) ändern.

Der zweite MsgBox-Aufruf zeigt "After replace(n): 11, 21, 31, 41" an. Da n nach Wert (ByVal) übergeben wird, kann replace die Variable n nicht durch Zuweisen eines neuen Arrays ändern. Wenn replace die neue Arrayinstanz k erstellt und der lokalen Variablen a zuweist, geht der Verweis auf n verloren, der vom aufrufenden Code übergeben wird. Wenn die Member von a erhöht werden, ist nur das lokale Array k betroffen.

Richtiger Ansatz: Um ein zugrunde liegendes Variablenelement selbst ändern zu können, übergeben Sie es durch Verweis. Das folgende Beispiel zeigt die Änderung in der Deklaration von replace, die es ermöglicht, ein Array durch ein anderes im aufrufenden Code zu ersetzen:

Public Sub replace(ByRef a() As Long)

Definieren einer Überladung nicht möglich

Wenn Sie eine überladene Version einer Prozedur definieren möchten, müssen Sie denselben Namen, aber eine andere Signatur verwenden. Wenn der Compiler Ihre Deklaration nicht von einer Überladung mit derselben Signatur unterscheiden kann, wird ein Fehler generiert.

Die Signatur einer Prozedur wird durch den Prozedurnamen und die Parameterliste bestimmt. Jede Überladung muss denselben Namen wie alle anderen Überladungen haben, muss sich jedoch von allen in mindestens einer der anderen Komponenten der Signatur unterscheiden. Weitere Informationen finden Sie unter Procedure Overloading.

Die folgenden Elemente sind keine Komponenten der Signatur einer Prozedur, auch wenn sie sich auf die Parameterliste beziehen:

  • Prozedurmodifizierer-Schlüsselwörter (z. B. Public, Shared und Static)
  • Parameternamen
  • Parametermodifizierer-Schlüsselwörter (z. B. ByRef und Optional)
  • Datentyp des Rückgabewerts (mit Ausnahme eines Konvertierungsoperators)

Sie können eine Prozedur nicht überladen, indem Sie nur eines oder mehrere der vorherigen Elemente abändern.

Richtiger Ansatz: Um eine Prozedurüberladung definieren zu können, müssen Sie die Signatur abändern. Da Sie denselben Namen verwenden müssen, müssen Sie die Anzahl, Reihenfolge oder Datentypen der Parameter abändern. In einer generischen Prozedur können Sie die Anzahl der Typparameter abändern. In einem Konvertierungsoperator (CType-Funktion) können Sie den Rückgabetyp abändern.

Überladungsauflösung mit Optional- und ParamArray-Argumenten

Wenn Sie eine Prozedur mit einem oder mehreren Optional-Parametern oder einem ParamArray-Parameter überladen, müssen Sie das Duplizieren impliziter Überladungen vermeiden. Weitere Informationen finden Sie unter Überlegungen zu überladenen Prozeduren.

Aufrufen der falschen Version einer überladenen Prozedur

Wenn eine Prozedur mehrere überladene Versionen umfasst, sollten Sie mit allen Parameterlisten vertraut sein und verstehen, wie Visual Basic Aufrufe zwischen den Überladungen löst. Andernfalls könnten Sie eine andere Überladung als die beabsichtigte aufrufen.

Wenn Sie festgestellt haben, welche Überladung Sie aufrufen möchten, beachten Sie die folgenden Regeln:

  • Geben Sie die richtige Anzahl von Argumenten und in der richtigen Reihenfolge an.
  • Im Idealfall sollten Ihre Argumente genau die gleichen Datentypen wie die entsprechenden Parameter aufweisen. In jedem Fall muss der Datentyp jedes Arguments auf den entsprechenden Parameter erweitert werden. Dies gilt auch dann, wenn die Option Strict-Anweisung auf Off festgelegt ist. Wenn eine Überladung eine einschränkende Konvertierung über die Argumentliste erfordert, kann diese Überladung nicht aufgerufen werden.
  • Wenn Sie Argumente angeben, die eine Erweiterung erfordern, legen Sie deren Datentypen so fest, dass diese den entsprechenden Parameterdatentypen möglichst ähneln. Wenn zwei oder mehr Überladungen die Argumentdatentypen akzeptieren, löst der Compiler den Aufruf der Überladung auf, die die geringste Erweiterung aufruft.

Sie können die Wahrscheinlichkeit von Datentypkonflikten reduzieren, indem Sie beim Aufbereiten Ihrer Argumente das Konvertierungsschlüsselwort der CType-Funktion verwenden.

Fehler bei der Überladungsauflösung

Wenn Sie eine überladene Prozedur aufrufen, versucht der Compiler, alle außer einer der Überladungen zu entfernen. Wenn er erfolgreich ist, wird der Aufruf dieser Überladung aufgelöst. Wenn alle Überladungen entfernt werden oder die verfügbaren Überladungen nicht auf eine einzelne Überladung reduziert werden können, wird ein Fehler generiert.

Im folgenden Beispiel wird der Überladungsauflösungsprozess veranschaulicht:

Overloads Sub z(ByVal x As Byte, ByVal y As Double)
End Sub
Overloads Sub z(ByVal x As Short, ByVal y As Single)
End Sub
Overloads Sub z(ByVal x As Integer, ByVal y As Single)
End Sub
Dim r, s As Short
Call z(r, s)
Dim p As Byte, q As Short
' The following statement causes an overload resolution error.
Call z(p, q)

Beim ersten Aufruf entfernt der Compiler die erste Überladung, da sich der Typ des ersten Arguments (Short) auf den Typ des entsprechenden Parameters (Byte) einschränkt. Anschließend wird die dritte Überladung entfernt, da jeder Argumenttyp in der zweiten Überladung (Short und Single) auf den entsprechenden Typ in der dritten Überladung (Integer und Single) erweitert wird. Die zweite Überladung erfordert eine geringere Erweiterung, sodass der Compiler sie für den Aufruf verwendet.

Im zweiten Aufruf kann der Compiler keine der Überladungen auf Grundlage der Einschränkung beseitigen. Er entfernt die dritte Überladung aus demselben Grund wie beim ersten Aufruf, weil die zweite Überladung mit einer geringeren Erweiterung der Argumenttypen aufgerufen werden kann. Der Compiler kann jedoch nicht zwischen der ersten und zweiten Überladung auflösen. Jede verfügt über einen definierten Parametertyp, der auf den entsprechenden Typ in der anderen Überladung erweitert wird (Byte auf Short, aber Single auf Double). Der Compiler generiert daher einen Überladungsauflösungsfehler.

Richtiger Ansatz: Um eine überladene Prozedur ohne Mehrdeutigkeit aufrufen zu können, verwenden Sie die CType-Funktion, um die Argumentdatentypen den Parametertypen zuzuordnen. Das folgende Beispiel veranschaulicht einen Aufruf von z, der die Auflösung für die zweite Überladung erzwingt.

Call z(CType(p, Short), CType(q, Single))

Überladungsauflösung mit Optional- und ParamArray-Argumenten

Wenn zwei Überladungen einer Prozedur identische Signaturen aufweisen, mit dem Unterschied, dass der letzte Parameter in der einen als Optional und in der anderen als ParamArray deklariert ist, löst der Compiler einen Aufruf dieser Prozedur entsprechend der größten Übereinstimmung auf. Weitere Informationen finden Sie unter Overload Resolution.

Weitere Informationen