Recherche…


Introduction

Les modificateurs ByRef et ByVal font partie de la signature d'une procédure et indiquent comment un argument est transmis à une procédure. Dans VBA, un paramètre est transmis à ByRef sauf indication contraire (c'est-à-dire que ByRef est implicite s'il est absent).

Remarque Dans de nombreux autres langages de programmation (y compris VB.NET), les paramètres sont implicitement passés par valeur si aucun modificateur n'est spécifié: envisagez de spécifier explicitement les modificateurs ByRef pour éviter toute confusion possible.

Remarques

Tableaux passants

Les tableaux doivent être transmis par référence. Ce code compile, mais déclenche l'erreur d'exécution 424 "Objet requis":

Public Sub Test()
    DoSomething Array(1, 2, 3)
End Sub

Private Sub DoSomething(ByVal foo As Variant)
    foo.Add 42
End Sub

Ce code ne compile pas:

Private Sub DoSomething(ByVal foo() As Variant) 'ByVal is illegal for arrays
    foo.Add 42
End Sub

Passer des variables simples ByRef et ByVal

Passage ByRef ou ByVal indique si la valeur réelle d'un argument est transmise à CalledProcedure par CallingProcedure ou si une référence (appelée pointeur dans d'autres langues) est transmise à CalledProcedure .

Si un argument est transmis à ByRef , l'adresse mémoire de l'argument est transmise à CalledProcedure et toute modification de ce paramètre par CalledProcedure est apportée à la valeur de la CallingProcedure .

Si un argument est transmis à ByVal , la valeur réelle, et non une référence à la variable, est transmise à la CalledProcedure .

Un exemple simple illustrera cela clairement:

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

Un autre exemple:

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


Modificateur par défaut

Si aucun modificateur n'est spécifié pour un paramètre, ce paramètre est implicitement transmis par référence.

Public Sub DoSomething1(foo As Long)
End Sub
Public Sub DoSomething2(ByRef foo As Long)
End Sub

Le paramètre foo est transmis à ByRef à la fois dans DoSomething1 et DoSomething2 .

Fais attention! Si vous venez à VBA avec l'expérience d'autres langues, c'est probablement le comportement opposé à celui auquel vous êtes habitué. Dans de nombreux autres langages de programmation (y compris VB.NET), le modificateur implicite / default transmet les paramètres par valeur.


En passant par référence

  • Lorsqu'une valeur est transmise par ByRef , la procédure reçoit une référence à la valeur.

    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
    

    L' appel ci - dessus Test des sorties de procédure 84. DoSomething est donné foo et reçoit une référence à la valeur, et travaille donc avec la même adresse de mémoire que l'appelant.

  • Lorsqu'une référence est transmise par ByRef , la procédure reçoit une référence au pointeur.

    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
    

    Le code ci-dessus génère l' erreur d'exécution 91 , car l'appelant appelle le membre Count d'un objet qui n'existe plus, car DoSomething a reçu une référence au pointeur d'objet et lui a attribué la valeur Nothing avant le renvoi.


Forçage de ByVal sur le site d'appel

En utilisant des parenthèses sur le site d'appel, vous pouvez remplacer ByRef et forcer le passage d'un argument 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

Le code ci-dessus produit 42, que ByRef soit spécifié implicitement ou explicitement.

Fais attention! De ce fait, l'utilisation de parenthèses superflues dans les appels de procédure peut facilement introduire des bogues. Faites attention aux espaces entre le nom de la procédure et la liste des arguments:

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

En passant par la valeur

  • Lorsqu'une valeur est transmise par ByVal , la procédure reçoit une copie de la valeur.

    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
    

    Appeler les Test procédure de Test ci-dessus 42. DoSomething se voit attribuer la valeur foo et reçoit une copie de la valeur. La copie est multipliée par 2, puis supprimée lorsque la procédure est terminée; la copie de l'appelant n'a jamais été modifiée.

  • Lorsqu'une référence est transmise à ByVal , la procédure reçoit une copie du pointeur.

    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
    

    Appel des Test procédure de Test ci-dessus 1. DoSomething se voit attribuer la valeur foo et reçoit une copie du pointeur sur l'objet Collection . Étant donné que la variable d'objet foo dans la portée Test pointe vers le même objet, l'ajout d'un élément dans DoSomething ajoute l'élément au même objet. Comme il s'agit d' une copie du pointeur, définir sa référence à Nothing n'affecte pas la copie de l'appelant.



Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow