Sök…


Introduktion

ByRef och ByVal modifierarna ingår i procedurens signatur och anger hur ett argument överförs till en procedur. I VBA passeras en parameter ByRef inte annat anges (dvs. ByRef är implicit om det inte finns).

Obs! På många andra programmeringsspråk (inklusive VB.NET) överförs parametrar implicit genom värde om ingen modifierare anges: överväga att specificera ByRef modifierare uttryckligen för att undvika eventuell förvirring.

Anmärkningar

Passerar matriser

Matriser måste skickas som referens. Den här koden kompilerar, men höjer körfel 424 "Objekt krävs":

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

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

Den här koden sammanställer inte:

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

Passing Simple Variables ByRef And ByVal

Att passera ByRef eller ByVal indikerar om det verkliga värdet på ett argument överförs till CalledProcedure av CallingProcedure , eller om en referens (kallas en pekare på vissa andra språk) skickas till CalledProcedure .

Om ett argument passeras ByRef , skickas ByRef minnesadress till CalledProcedure och alla ändringar av den parametern av CalledProcedure görs till värdet i CallingProcedure .

Om ett argument passeras ByVal , ByVal det verkliga värdet, inte en referens till variabeln, till CalledProcedure .

Ett enkelt exempel illustrerar detta tydligt:

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

Ett annat exempel:

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


Standardmodifierare

Om ingen modifierare anges för en parameter, överförs den parametern implicit genom referens.

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

foo parametern överförs ByRef i både DoSomething1 och DoSomething2 .

Se upp! Om du kommer till VBA med erfarenhet från andra språk är det mycket troligtvis det motsatta beteendet än det du är van vid. På många andra programmeringsspråk (inklusive VB.NET) överför den implicita / standardmodifieraren parametrar efter värde.


Skickas genom referens

  • När ett värde passeras ByRef får proceduren en referens till värdet.

    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
    

    Anropa ovan Test procedur utmatar 84. DoSomething ges foo och mottar en referens till värdet, och arbetar därför med samma minnesadress som den som ringer.

  • När en referens passeras ByRef får proceduren en referens till pekaren.

    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
    

    Ovanstående kod väcker körtidfel 91 , eftersom uppringaren ringer Count för ett objekt som inte längre finns, eftersom DoSomething fick en referens till objektpekaren och tilldelades det till Nothing innan han återvände.


Tvinga ByVal på samtalssidan

Med hjälp av parenteser på samtalssidan kan du åsidosätta ByRef och tvinga ett argument att skickas 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

Ovanstående kod matar ut 42, oavsett om ByRef anges implicit eller uttryckligen.

Se upp! På grund av detta kan användning av främmande parenteser i procedursamtal enkelt införa buggar. Var uppmärksam på mellanrummet mellan procedurnamnet och argumentlistan:

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

Passerar efter värde

  • När ett värde passeras ByVal får proceduren en kopia av värdet.

    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
    

    Anropa ovan Test procedur utmatar 42. DoSomething ges foo och mottar en kopia av värdet. Kopian multipliceras med 2 och kastas sedan när proceduren går ut. samtalens kopia ändrades aldrig.

  • När en referens passeras ByVal får proceduren en kopia av pekaren.

    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
    

    Anropa ovan Test utmatar 1. DoSomething ges foo och mottar en kopia av pekaren till Collection objektet. Eftersom foo objektvariabeln i Test omfattning pekar på samma objekt, lägga ett objekt i DoSomething adderar objektet till samma objekt. Eftersom det är en kopia av pekaren påverkar inte inställarens egna kopia att ställa in referensen till Nothing .



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow