수색…


소개

ByRefByVal 수정자는 프로 시저의 서명의 일부이며 인수가 프로 시저로 전달되는 방법을 나타냅니다. VBA에서는 매개 변수가 달리 지정되지 않는 한 ByRef 가 전달됩니다 (즉, ByRef 는 부재시 암시 적입니다).

참고 다른 프로그래밍 언어 (VB.NET 포함)에서는 수정자가 지정되지 않은 경우 매개 변수가 값에 의해 암시 적으로 전달됩니다. 혼동을 피하기 위해 ByRef 한정자를 명시 적으로 지정하는 것이 좋습니다.

비고

전달 배열

배열 참조로 전달 되어야합니다 . 이 코드는 컴파일되지만 런타임 오류 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

이 코드는 컴파일되지 않습니다.

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

간단한 변수 ByRef 및 ByVal 전달

전달 ByRef 또는 ByVal 인자의 실제 값에 전달되는지 여부를 나타내는 CalledProcedure 의해 CallingProcedure 또는 (다른 언어 포인터라고 함)가 참조로 전달 여부 CalledProcedure .

인수가 ByRef 전달하면 인수의 메모리 주소가 CalledProcedure 전달되고 CalledProcedure 의해 해당 매개 변수에 대한 수정이 CalledProcedure 의 값으로 수행 CallingProcedure .

인수가 ByVal 전달하면 변수에 대한 참조가 아닌 실제 값이 CalledProcedure 전달됩니다.

간단한 예가이를 명확하게 보여줍니다 :

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

다른 예시:

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


기본 수정 자

매개 변수에 수정자가 지정되지 않은 경우 해당 매개 변수는 참조에 의해 암시 적으로 전달됩니다.

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

foo 매개 변수는 DoSomething1DoSomething2 모두에서 ByRef 를 전달합니다.

조심해! 다른 언어로 된 경험이있는 VBA에 오시는 경우, 지금까지 익숙한 것과는 정반대의 행동 일 가능성이 큽니다. 다른 많은 프로그래밍 언어 (VB.NET 포함)에서 암시 적 / 기본 수정자는 매개 변수를 값으로 전달합니다.


참조로 전달

  • ByRef 을 전달하면 프로 시저는 값에 대한 참조 를받습니다.

    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
    

    위의 Test 프로 시저를 호출하면 84가 출력됩니다. DoSomethingfoo 가 주어지고 값에 대한 참조 를 수신하므로 호출자와 동일한 메모리 주소로 작동합니다.

  • 참조ByRef 전달하면 프로 시저는 포인터에 대한 참조 를받습니다.

    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
    

    위 코드는 호출자가 더 이상 존재하지 않는 개체의 Count 멤버를 호출하기 때문에 런타임 오류 91을 발생시킵니다 . 왜냐하면 DoSomething 이 개체 포인터에 대한 참조 를 받고 반환하기 전에 Nothing 할당했기 때문입니다.


강제 호출 사이트에서 ByVal

호출 사이트에서 괄호를 사용하면 ByRef 를 재정 의하여 인수를 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

위의 코드는 ByRef 가 암시 적으로 또는 명시 적으로 지정되었는지 여부에 관계없이 42를 출력합니다.

조심해! 따라서 프로 시저 호출에서 외부 괄호를 사용하면 쉽게 버그가 발생할 수 있습니다. 프로 시저 이름과 인수 목록 사이의 공백에주의하십시오.

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

가치 전달

  • ByVal 에 전달되면 프로 시저는 값 의 복사본 을받습니다.

    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
    

    위의 Test 프로 시저를 호출하면 42가 출력됩니다. DoSomethingfoo 가 주어지고 값 의 복사본 을받습니다. 복사본에 2를 곱한 다음 프로 시저가 끝나면 폐기됩니다. 발신자의 복사본이 변경되지 않았습니다.

  • 참조ByVal 전달 될 때 프로 시저 포인터 의 복사본 을받습니다.

    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
    

    위의 Test 프로 시저를 호출하면 DoSomethingfoo 로 주어지고 Collection 객체에 대한 포인터 복사본 을받습니다. Test 범위의 foo 객체 변수가 동일한 객체를 가리 DoSomething 때문에 DoSomething 에 항목을 추가하면 항목이 동일한 객체에 추가됩니다. 포인터 의 복사본 이기 때문에 참조를 Nothing 설정해도 호출자의 복사본에는 영향을주지 않습니다.



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow