VBA
Argumenten doorgeven ByRef of ByVal
Zoeken…
Invoering
De ByRef en ByVal maken deel uit van de handtekening van een procedure en geven aan hoe een argument wordt doorgegeven aan een procedure. In VBA wordt een parameter doorgegeven aan ByRef tenzij anders aangegeven (dwz ByRef is impliciet indien afwezig).
Opmerking In veel andere programmeertalen (inclusief VB.NET) worden parameters impliciet doorgegeven als er geen modifier is opgegeven: overweeg om ByRef modifiers expliciet op te geven om mogelijke verwarring te voorkomen.
Opmerkingen
Arrays passeren
Arrays moeten worden doorgegeven door middel van verwijzing. Deze code wordt gecompileerd, maar veroorzaakt runtime-fout 424 "Object vereist":
Public Sub Test()
DoSomething Array(1, 2, 3)
End Sub
Private Sub DoSomething(ByVal foo As Variant)
foo.Add 42
End Sub
Deze code bestaat niet uit:
Private Sub DoSomething(ByVal foo() As Variant) 'ByVal is illegal for arrays
foo.Add 42
End Sub
Eenvoudige variabelen doorgeven ByRef en ByVal
Passing ByRef of ByVal geeft aan of de werkelijke waarde van een argument door de CallingProcedure aan de CalledProcedure wordt doorgegeven, of dat een verwijzing (in sommige andere talen een pointer genoemd) wordt doorgegeven aan de CalledProcedure .
Als een argument door ByRef wordt doorgegeven, wordt het geheugenadres van het argument doorgegeven aan de CalledProcedure en wordt elke wijziging in die parameter door de CalledProcedure aangebracht aan de waarde in de CallingProcedure .
Als een argument wordt doorgegeven ByVal , wordt de werkelijke waarde, niet een verwijzing naar de variabele, doorgegeven aan de CalledProcedure .
Een eenvoudig voorbeeld zal dit duidelijk illustreren:
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
Een ander voorbeeld:
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
Standaard modifier
Als er geen modifier is opgegeven voor een parameter, wordt die parameter impliciet doorgegeven als referentie.
Public Sub DoSomething1(foo As Long)
End Sub
Public Sub DoSomething2(ByRef foo As Long)
End Sub
De parameter foo wordt doorgegeven ByRef in zowel DoSomething1 als DoSomething2 .
Kijk uit! Als je naar VBA komt met ervaring uit andere talen, is dit waarschijnlijk precies het tegenovergestelde gedrag dan je gewend bent. In veel andere programmeertalen (inclusief VB.NET) geeft de impliciete / standaard modifier parameters door aan waarde.
Doorgeven door referentie
Wanneer een waarde aan
ByRefwordt doorgegeven, ontvangt de procedure een verwijzing naar de waarde.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 SubRoept de bovenstaande
Testprocedure uitvoert 84.DoSomethinggegevenfooen een verwijzing naar de waarde ontvangt en dus werkt met hetzelfde geheugenadres als de beller.Wanneer een referentie aan
ByRefwordt doorgegeven, ontvangt de procedure een verwijzing naar de aanwijzer.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 SubDe bovenstaande code roept runtime-fout 91 op , omdat de beller het
Countlid van een object oproept dat niet langer bestaat, omdatDoSomethingeen verwijzing naar deDoSomethinggekregen en deze aanNothingtoegewezen voordat deze terugkeerde.
ByVal forceren op oproepsite
Met haakjes op de oproepsite kunt u ByRef overschrijven en een argument dwingen 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
De bovenstaande code voert 42 uit, ongeacht of ByRef impliciet of expliciet is gespecificeerd.
Kijk uit! Daarom kan het gebruik van vreemde haakjes bij procedureaanroepen gemakkelijk bugs introduceren. Let op de witruimte tussen de procedurenaam en de lijst met argumenten:
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
Waarde doorgeven
Wanneer een waarde wordt doorgegeven
ByVal, ontvangt de procedure een kopie van de waarde.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 SubRoept de bovenstaande
Testprocedure uitvoert 42.DoSomethinggegevenfooen een kopie van de waarde ontvangt. De kopie wordt vermenigvuldigd met 2 en vervolgens verwijderd wanneer de procedure wordt afgesloten; het exemplaar van de beller is nooit gewijzigd.Wanneer een verwijzing door
ByValwordt doorgegeven, ontvangt de procedure een kopie van de aanwijzer.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 SubRoept de bovenstaande
Testprocedure uitvoert 1.DoSomethinggegevenfooen ontvangt een kopie van de wijzer naar hetCollectionobject. Omdat defooobjectvariabele in deTestbereik verwijst naar hetzelfde object, het toevoegen van een objectDoSomethingvoegt de punt naar hetzelfde object. Omdat het een kopie van de aanwijzer is, heeft het instellen van de verwijzing naarNothinggeen invloed op de kopie van de beller.