문제 해결 절차(Visual Basic)

이 페이지에는 프로시저를 사용할 때 발생할 수 있는 몇 가지 일반적인 문제가 나열됩니다.

함수 프로시저에서 배열 형식 반환

프로시저가 Function 배열 데이터 형식을 반환하는 경우 이름을 사용하여 Function 배열의 요소에 값을 저장할 수 없습니다. 이 작업을 시도하면 컴파일러는 이를 에 대한 호출 Function로 해석합니다. 다음 예제에서는 컴파일러 오류를 생성합니다.

Function AllOnes(n As Integer) As Integer()
   For i As Integer = 1 To n - 1  
      ' The following statement generates a COMPILER ERROR.  
      AllOnes(i) = 1  
   Next  

   ' The following statement generates a COMPILER ERROR.  
   Return AllOnes()  
End Function

AllOnes(i) = 1 은 잘못된 데이터 형식(배열 대신 Integer 스칼라Integer)의 인수를 사용하여 를 호출 AllOnes 하는 것처럼 보이기 때문에 컴파일러 오류를 생성합니다. 문 Return AllOnes() 은 인수 없이 를 호출 AllOnes 하는 것처럼 보이기 때문에 컴파일러 오류를 생성합니다.

올바른 접근 방식: 반환할 배열의 요소를 수정하려면 내부 배열을 지역 변수로 정의합니다. 다음 예제에서는 오류 없이 컴파일합니다.

Function AllOnes(n As Integer) As Integer()
    Dim iArray(n - 1) As Integer
    For i = 0 To n - 1
        iArray(i) = 1
    Next
    Return iArray
End Function

프로시저 호출로 수정되지 않은 인수

프로시저가 호출 코드에서 인수의 기반이 되는 프로그래밍 요소를 변경하도록 허용하려면 참조로 전달해야 합니다. 그러나 프로시저는 값으로 전달하더라도 참조 형식 인수의 요소에 액세스할 수 있습니다.

  • 기본 변수입니다. 프로시저가 기본 변수 요소 자체의 값을 바꿀 수 있도록 하려면 프로시저에서 ByRef 매개 변수를 선언해야 합니다. 또한 호출 코드는 전달 메커니즘을 재정의하므로 인수를 괄호로 ByRef 묶어서는 안 됩니다.

  • 참조 형식 요소입니다. ByVal 매개 변수를 선언하는 경우 프로시저는 기본 변수 요소 자체를 수정할 수 없습니다. 그러나 인수가 참조 형식인 경우 프로시저는 변수의 값을 바꿀 수 없더라도 가리키는 개체의 멤버를 수정할 수 있습니다. 예를 들어 인수가 배열 변수인 경우 프로시저는 새 배열을 할당할 수 없지만 하나 이상의 요소를 변경할 수 있습니다. 변경된 요소는 호출 코드의 기본 배열 변수에 반영됩니다.

다음 예제에서는 배열 변수를 값으로 사용하고 해당 요소에서 작동하는 두 가지 프로시저를 정의합니다. 프로시저 increase 는 각 요소에 하나만 추가합니다. 프로시저 replace 는 매개 변수 a() 에 새 배열을 할당한 다음 각 요소에 배열을 추가합니다. 그러나 는 로 선언ByVal되므로 재할당은 호출 코드 a() 의 기본 배열 변수에 영향을 주지 않습니다.

Public Sub increase(ByVal a() As Long)
    For j As Integer = 0 To UBound(a)
        a(j) = a(j) + 1
    Next j
End Sub
Public Sub replace(ByVal a() As Long)
    Dim k() As Long = {100, 200, 300}
    a = k
    For j As Integer = 0 To UBound(a)
        a(j) = a(j) + 1
    Next j
End Sub

다음 예제에서는 및 replace를 호출합니다increase.

Dim n() As Long = {10, 20, 30, 40}
Call increase(n)
MsgBox("After increase(n): " & CStr(n(0)) & ", " & 
    CStr(n(1)) & ", " & CStr(n(2)) & ", " & CStr(n(3)))
Call replace(n)
MsgBox("After replace(n): " & CStr(n(0)) & ", " & 
    CStr(n(1)) & ", " & CStr(n(2)) & ", " & CStr(n(3)))

첫 번째 MsgBox 호출은 "증가 후(n): 11, 21, 31, 41"을 표시합니다. n 는 참조 형식이므로 는 increase 전달되ByVal더라도 해당 멤버를 변경할 수 있습니다.

두 번째 MsgBox 호출은 "After replace(n): 11, 21, 31, 41"을 표시합니다. n 가 전달되므로 ByValreplace 변수에 새 배열을 할당하여 변수 n 를 수정할 수 없습니다. replace 새 배열 instance k 만들어서 지역 변수a에 할당하면 호출 코드에서 전달되는 에 대한 참조 n 가 손실됩니다. 의 a멤버가 증가하면 로컬 배열 k 만 영향을 받습니다.

올바른 접근 방식: 기본 변수 요소 자체를 수정하려면 참조로 전달합니다. 다음 예제에서는 호출 코드에서 한 배열을 다른 배열로 바꿀 수 있는 선언 replace 의 변경 내용을 보여 줍니다.

Public Sub replace(ByRef a() As Long)

오버로드를 정의할 수 없음

프로시저의 오버로드된 버전을 정의하려면 이름이 같지만 다른 서명을 사용해야 합니다. 컴파일러가 동일한 서명을 가진 오버로드와 선언을 구분할 수 없는 경우 오류가 발생합니다.

프로시저의 서명 은 프로시저 이름과 매개 변수 목록에 따라 결정됩니다. 각 오버로드는 다른 모든 오버로드와 이름이 동일해야 하지만 서명의 다른 구성 요소 중 하나 이상에서 모든 오버로드와 달라야 합니다. 자세한 내용은 Procedure Overloading을 참조하세요.

매개 변수 목록과 관련된 다음 항목은 프로시저 서명의 구성 요소가 아닙니다.

  • 프로시저 한정자 키워드(예: Public, SharedStatic).
  • 매개 변수 이름입니다.
  • 매개 변수 한정자 키워드(예: ByRefOptional).
  • 반환 값의 데이터 형식입니다(변환 연산자 제외).

이전 항목 중 하나 이상만 변경하여 프로시저를 오버로드할 수 없습니다.

올바른 접근 방식: 프로시저 오버로드를 정의하려면 서명을 변경해야 합니다. 동일한 이름을 사용해야 하므로 매개 변수의 수, 순서 또는 데이터 형식을 변경해야 합니다. 제네릭 프로시저에서는 형식 매개 변수의 수를 변경할 수 있습니다. 변환 연산자(CType 함수)에서는 반환 형식을 변경할 수 있습니다.

선택적 인수 및 ParamArray 인수를 사용하여 오버로드 확인

하나 이상의 선택적 매개 변수 또는 ParamArray 매개 변수를 사용하여 프로시저를 오버로드하는 경우 암시적 오버로드가 중복되지 않도록 해야 합니다. 자세한 내용은 오버로드 프로시저의 고려 사항을 참조하세요.

오버로드된 프로시저의 잘못된 버전 호출

프로시저에 오버로드된 버전이 여러 개 있는 경우 모든 매개 변수 목록에 익숙하고 Visual Basic이 오버로드 간의 호출을 확인하는 방법을 이해해야 합니다. 그렇지 않으면 의도한 오버로드가 아닌 오버로드를 호출할 수 있습니다.

호출할 오버로드를 결정한 경우 다음 규칙을 준수해야 합니다.

  • 올바른 수의 인수를 올바른 순서로 입력합니다.
  • 이상적으로 인수에는 해당 매개 변수와 정확히 동일한 데이터 형식이 있어야 합니다. 어쨌든 각 인수의 데이터 형식은 해당 매개 변수의 데이터 형식으로 확장되어야 합니다. Option Strict 문이 로 설정된 Off경우에도 마찬가지입니다. 오버로드에 인수 목록에서 축소 변환이 필요한 경우 해당 오버로드를 호출할 수 없습니다.
  • 확대가 필요한 인수를 제공하는 경우 해당 데이터 형식을 해당 매개 변수 데이터 형식에 최대한 가깝게 만듭니다. 두 개 이상의 오버로드가 인수 데이터 형식을 수락하면 컴파일러는 최소 확장량을 호출하는 오버로드에 대한 호출을 확인합니다.

인수를 준비할 때 CType 함수 변환 키워드(keyword) 사용하여 데이터 형식 불일치 가능성을 줄일 수 있습니다.

오버로드 확인 실패

오버로드된 프로시저를 호출할 때 컴파일러는 오버로드 중 하나를 제외한 모든 것을 제거하려고 시도합니다. 성공하면 해당 오버로드에 대한 호출이 해결됩니다. 모든 오버로드를 제거하거나 적격 오버로드를 단일 후보로 줄일 수 없는 경우 오류가 발생합니다.

다음 예제에서는 오버로드 확인 프로세스를 보여 줍니다.

Overloads Sub z(ByVal x As Byte, ByVal y As Double)
End Sub
Overloads Sub z(ByVal x As Short, ByVal y As Single)
End Sub
Overloads Sub z(ByVal x As Integer, ByVal y As Single)
End Sub
Dim r, s As Short
Call z(r, s)
Dim p As Byte, q As Short
' The following statement causes an overload resolution error.
Call z(p, q)

첫 번째 호출에서 컴파일러는 첫 번째 인수()의 형식이 해당 매개 변수(ShortByte)의 형식으로 좁아지므로 첫 번째 오버로드를 제거합니다. 그런 다음 두 번째 오버로드( 및 )의 각 인수 형식이 세 번째 오버로드(ShortIntegerSingleSingle)의 해당 형식으로 확장되므로 세 번째 오버로드를 제거합니다. 두 번째 오버로드는 더 적은 확장이 필요하므로 컴파일러는 호출에 이를 사용합니다.

두 번째 호출에서 컴파일러는 축소를 기반으로 오버로드를 제거할 수 없습니다. 인수 형식의 확장이 적은 두 번째 오버로드를 호출할 수 있으므로 첫 번째 호출과 동일한 이유로 세 번째 오버로드를 제거합니다. 그러나 컴파일러는 첫 번째 오버로드와 두 번째 오버로드 간에 resolve 수 없습니다. 각 매개 변수 형식에는 정의된 매개 변수 형식이 하나씩 있으며, 다른 형식의 해당 형식으로 확장됩니다(에서 로ByteShort,하지만 SingleDouble). 따라서 컴파일러는 오버로드 확인 오류를 생성합니다.

올바른 접근 방식: 모호성 없이 오버로드된 프로시저를 호출하려면 CType 함수 를 사용하여 인수 데이터 형식을 매개 변수 형식과 일치합니다. 다음 예제에서는 두 번째 오버로드에 z 대한 확인을 강제하는 에 대한 호출을 보여줍니다.

Call z(CType(p, Short), CType(q, Single))

선택적 인수 및 ParamArray 인수를 사용하여 오버로드 확인

프로시저의 두 오버로드에 동일한 서명이 있는 경우 마지막 매개 변수가 한 매개 변수에서 선택적으로 선언되고 다른 하나는 ParamArray 로 선언된다는 점을 제외하고 컴파일러는 가장 가까운 일치 항목에 따라 해당 프로시저에 대한 호출을 확인합니다. 자세한 내용은 Overload Resolution을 참조하세요.

참고 항목