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 ByRef wordt 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 Sub
    

    Roept de bovenstaande Test procedure uitvoert 84. DoSomething gegeven foo en een verwijzing naar de waarde ontvangt en dus werkt met hetzelfde geheugenadres als de beller.

  • Wanneer een referentie aan ByRef wordt 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 Sub
    

    De bovenstaande code roept runtime-fout 91 op , omdat de beller het Count lid van een object oproept dat niet langer bestaat, omdat DoSomething een verwijzing naar de DoSomething gekregen en deze aan Nothing toegewezen 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 Sub
    

    Roept de bovenstaande Test procedure uitvoert 42. DoSomething gegeven foo en 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 ByVal wordt 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 Sub
    

    Roept de bovenstaande Test procedure uitvoert 1. DoSomething gegeven foo en ontvangt een kopie van de wijzer naar het Collection object. Omdat de foo objectvariabele in de Test bereik verwijst naar hetzelfde object, het toevoegen van een object DoSomething voegt de punt naar hetzelfde object. Omdat het een kopie van de aanwijzer is, heeft het instellen van de verwijzing naar Nothing geen invloed op de kopie van de beller.



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow