VBA
Argumente übergeben ByRef oder ByVal
Suche…
Einführung
Die Modifizierer ByRef und ByVal sind Teil der Signatur einer Prozedur und geben an, wie ein Argument an eine Prozedur übergeben wird. In VBA wird ein Parameter an ByRef sofern nichts anderes angegeben ist (dh ByRef ist implizit, falls nicht vorhanden).
Hinweis In vielen anderen Programmiersprachen (einschließlich VB.NET) werden Parameter implizit durch einen Wert übergeben, wenn kein Modifikator angegeben ist. Sie ByRef explizit ByRef Modifikatoren angeben, um mögliche Verwirrungen zu vermeiden.
Bemerkungen
Arrays übergeben
Arrays müssen als Referenz übergeben werden. Dieser Code wird kompiliert, verursacht jedoch den Laufzeitfehler 424 "Object Required":
Public Sub Test()
DoSomething Array(1, 2, 3)
End Sub
Private Sub DoSomething(ByVal foo As Variant)
foo.Add 42
End Sub
Dieser Code kompiliert nicht:
Private Sub DoSomething(ByVal foo() As Variant) 'ByVal is illegal for arrays
foo.Add 42
End Sub
Einfache Variablen übergeben ByRef und ByVal
Übergeben von ByRef oder ByVal gibt an, ob der tatsächliche Wert eines Arguments von CalledProcedure an CallingProcedure wird oder ob eine Referenz (in anderen Sprachen als Zeiger bezeichnet) an CalledProcedure .
Wenn ein Argument ByRef , wird die Speicheradresse des Arguments an die CalledProcedure und alle Änderungen an diesem Parameter durch die CalledProcedure an dem Wert in der CallingProcedure .
Wenn ein Argument ByVal , wird der tatsächliche Wert, nicht ein Verweis auf die Variable, an die CalledProcedure .
Ein einfaches Beispiel veranschaulicht dies deutlich:
Sub CalledProcedure(ByRef X As Long, ByVal Y As Long)
X = 321
Y = 654
End Sub
Sub CallingProcedure()
Dim A As Long
Dim B As Long
A = 123
B = 456
Debug.Print "BEFORE CALL => A: " & CStr(A), "B: " & CStr(B)
''Result : BEFORE CALL => A: 123 B: 456
CalledProcedure X:=A, Y:=B
Debug.Print "AFTER CALL = A: " & CStr(A), "B: " & CStr(B)
''Result : AFTER CALL => A: 321 B: 456
End Sub
Ein anderes Beispiel:
Sub Main()
Dim IntVarByVal As Integer
Dim IntVarByRef As Integer
IntVarByVal = 5
IntVarByRef = 10
SubChangeArguments IntVarByVal, IntVarByRef '5 goes in as a "copy". 10 goes in as a reference
Debug.Print "IntVarByVal: " & IntVarByVal 'prints 5 (no change made by SubChangeArguments)
Debug.Print "IntVarByRef: " & IntVarByRef 'prints 99 (the variable was changed in SubChangeArguments)
End Sub
Sub SubChangeArguments(ByVal ParameterByVal As Integer, ByRef ParameterByRef As Integer)
ParameterByVal = ParameterByVal + 2 ' 5 + 2 = 7 (changed only inside this Sub)
ParameterByRef = ParameterByRef + 89 ' 10 + 89 = 99 (changes the IntVarByRef itself - in the Main Sub)
End Sub
ByRef
Standardmodifikator
Wenn für einen Parameter kein Modifikator angegeben ist, wird dieser Parameter implizit als Referenz übergeben.
Public Sub DoSomething1(foo As Long)
End Sub
Public Sub DoSomething2(ByRef foo As Long)
End Sub
Der foo Parameter übergeben wird ByRef sowohl in DoSomething1 und DoSomething2 .
Achtung! Wenn Sie mit Erfahrungen aus anderen Sprachen zu VBA kommen, ist dies sehr wahrscheinlich das genaue Gegenteil von dem, das Sie gewohnt sind. In vielen anderen Programmiersprachen (einschließlich VB.NET) übergibt der implizite / default-Modifikator Parameter nach Wert.
Übergabe als Referenz
Wenn ein Wert
ByRef, erhält die Prozedur einen Verweis auf den Wert.Public Sub Test() Dim foo As Long foo = 42 DoSomething foo Debug.Print foo End Sub Private Sub DoSomething(ByRef foo As Long) foo = foo * 2 End SubDer Aufruf der oben
Test- Prozedur Ausgänge 84.DoSomethingist gegebenfoound erhält einen Verweis auf den Wert, und deshalb arbeitet mit der gleichen Speicheradresse wie der Aufrufer.Wenn eine Referenz
ByRef, erhält die Prozedur eine Referenz auf den Zeiger.Public Sub Test() Dim foo As Collection Set foo = New Collection DoSomething foo Debug.Print foo.Count End Sub Private Sub DoSomething(ByRef foo As Collection) foo.Add 42 Set foo = Nothing End SubDer obige Code verursacht einen Laufzeitfehler 91 , da der Aufrufer das
CountDoSomethingeines Objekts aufruft, das nicht mehr vorhanden ist, weilDoSomethingvor dem Zurückgeben einen Verweis auf den Objektzeiger erhalten und diesemNothingzugewiesen hat.
ByVal am Anrufort erzwingen
Mit Klammern an der Aufrufstelle können Sie ByRef überschreiben und die ByRef eines Arguments für ByVal :
Public Sub Test()
Dim foo As Long
foo = 42
DoSomething (foo)
Debug.Print foo
End Sub
Private Sub DoSomething(ByRef foo As Long)
foo = foo * 2
End Sub
Der obige Code gibt 42 aus, unabhängig davon, ob ByRef implizit oder explizit angegeben wird.
Achtung! Aus diesem Grund kann die Verwendung fremder Klammern in Prozeduraufrufen leicht zu Fehlern führen. Achten Sie auf den Leerraum zwischen dem Prozedurnamen und der Argumentliste:
bar = DoSomething(foo) 'function call, no whitespace; parens are part of args list DoSomething (foo) 'procedure call, notice whitespace; parens are NOT part of args list DoSomething foo 'procedure call does not force the foo parameter to be ByVal
ByVal
Übergabe nach Wert
Wenn ein Wert
ByVal, erhält die Prozedur eine Kopie des Werts.Public Sub Test() Dim foo As Long foo = 42 DoSomething foo Debug.Print foo End Sub Private Sub DoSomething(ByVal foo As Long) foo = foo * 2 End SubDer Aufruf der oben
Test- Prozedur Ausgänge 42.DoSomethingist gegebenfoound erhält eine Kopie des Wertes. Die Kopie wird mit 2 multipliziert und dann verworfen, wenn die Prozedur beendet wird. Die Kopie des Anrufers wurde nie geändert.Wenn eine Referenz
ByVal, erhält die Prozedur eine Kopie des Zeigers.Public Sub Test() Dim foo As Collection Set foo = New Collection DoSomething foo Debug.Print foo.Count End Sub Private Sub DoSomething(ByVal foo As Collection) foo.Add 42 Set foo = Nothing End SubAufrufen der obigen
Test- Verfahren 1. AusgängeDoSomethinggegebenfoound erhält eine Kopie des Zeigers auf dieCollectionObjekt. Da diefooObjektvariable in denTest- Umfang Punkte auf das gleiche Objekt, ein Element in das HinzufügenDoSomethingfügt das Element auf das gleiche Objekt. Da es sich um eine Kopie des Zeigers handelt, wirkt sich die Einstellung des Verweises aufNothingnicht auf die eigene Kopie des Aufrufers aus.