Поделиться через


Процедуры устранения неполадок (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 создает ошибку компилятора, так как она вызывается AllOnes с аргументом неправильного типа данных (скаляр Integer , а не Integer массив). Инструкция 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() новый массив, а затем добавляет по одному к каждому элементу. Однако переназначение не влияет на базовую переменную массива в вызывающем коде, так как a() объявляется ByVal.

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

В следующем примере выполняется increase вызов и replace.

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 вызове отображается сообщение "After increase(n): 11, 21, 31, 41". Поскольку n является ссылочным типом, increase может изменять его члены, даже если он передается ByVal.

Во втором MsgBox вызове отображается сообщение "After replace(n): 11, 21, 31, 41". Так как n передается ByVal, replace не может изменить переменную n , назначив ей новый массив. Когда replace создает новый экземпляр k массива и назначает его локальной переменной a, он теряет ссылку n на , переданную вызывающим кодом. При приращении членов aзатрагивается только локальный массив k .

Правильный подход: Чтобы иметь возможность изменять сам элемент базовой переменной, передайте его по ссылке. В следующем примере показано изменение в объявлении , позволяющее replace заменить один массив другим в вызывающем коде:

Public Sub replace(ByRef a() As Long)

Не удается определить перегрузку

Если вы хотите определить перегруженную версию процедуры, необходимо использовать то же имя, но другую сигнатуру. Если компилятор не может отличить объявление от перегрузки с той же сигнатурой, возникает ошибка.

Подпись процедуры определяется именем процедуры и списком параметров. Каждая перегрузка должна иметь то же имя, что и все остальные перегрузки, но должна отличаться от всех этих перегрузок по крайней мере одним из других компонентов сигнатуры. Дополнительные сведения см. в разделе Procedure Overloading.

Следующие элементы, даже если они относятся к списку параметров, не являются компонентами сигнатуры процедуры:

  • Ключевые слова модификатора процедуры, такие как Public, Sharedи Static.
  • Имена параметров.
  • Ключевые слова модификатора параметров, такие как ByRef и Optional.
  • Тип данных возвращаемого значения (за исключением оператора преобразования).

Нельзя перегружать процедуру, изменяя только один или несколько предыдущих элементов.

Правильный подход: Чтобы определить перегрузку процедуры, необходимо изменить сигнатуру. Так как необходимо использовать одно и то же имя, необходимо изменить число, порядок или типы данных параметров. В универсальной процедуре можно изменить количество параметров типа. В операторе преобразования (функция CType) можно изменять тип возвращаемого значения.

Разрешение перегрузки с помощью аргументов Optional и ParamArray

При перегрузке процедуры одним или несколькими необязательными параметрами или параметром ParamArray необходимо избегать дублирования неявных перегрузок. Дополнительные сведения см. в разделе Рекомендации в разделе Процедуры перегрузки.

Вызов неправильной версии перегруженной процедуры

Если процедура имеет несколько перегруженных версий, вы должны быть знакомы со всеми их списками параметров и понимать, как Visual Basic разрешает вызовы между перегрузками. В противном случае можно вызвать перегрузку, отличаемую от предполагаемой.

Определив, какую перегрузку требуется вызвать, соблюдайте следующие правила.

  • Укажите правильное количество аргументов и в правильном порядке.
  • В идеале аргументы должны иметь те же типы данных, что и соответствующие параметры. В любом случае тип данных каждого аргумента должен быть расширен до типа соответствующего параметра. Это верно, даже если оператор Option Strict имеет значение Off. Если перегрузка требует какого-либо сужающего преобразования из списка аргументов, эта перегрузка не может быть вызвана.
  • Если вы предоставляете аргументы, требующие расширения, сделайте их типы данных как можно ближе к соответствующим типам данных параметров. Если две или более перегрузки принимают типы данных аргументов, компилятор разрешает вызов перегрузке, вызывающей наименьшее расширение.

Вы можете снизить вероятность несоответствия типов данных с помощью ключевое слово преобразования функции CType при подготовке аргументов.

Сбой разрешения перегрузки

При вызове перегруженной процедуры компилятор пытается устранить все перегрузки, кроме одной. В случае успешного выполнения вызов этой перегрузки разрешается. Если он устраняет все перегрузки или не может уменьшить допустимые перегрузки до одного кандидата, возникает ошибка.

В следующем примере показан процесс разрешения перегрузки:

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)

В первом вызове компилятор устраняет первую перегрузку, так как тип первого аргумента (Short) сужается до типа соответствующего параметра (Byte). Затем он устраняет третью перегрузку, так как каждый тип аргумента во второй перегрузке (Short и Single) расширяется до соответствующего типа в третьей перегрузке (Integer и Single). Вторая перегрузка требует меньшего расширения, поэтому компилятор использует ее для вызова .

Во втором вызове компилятор не может устранить какие-либо перегрузки на основе сужения. Он устраняет третью перегрузку по той же причине, что и в первом вызове, так как может вызывать вторую перегрузку с меньшим расширением типов аргументов. Однако компилятор не может разрешиться между первой и второй перегрузками. Каждый из них имеет один определенный тип параметра, который расширяется до соответствующего типа в другом (Byte до Short, но Single до Double). Таким образом, компилятор создает ошибку разрешения перегрузки.

Правильный подход: Чтобы иметь возможность вызывать перегруженную процедуру без неоднозначности, используйте функцию CType для сопоставления типов данных аргументов с типами параметров. В следующем примере показан вызов этого z принудительного разрешения для второй перегрузки.

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

Разрешение перегрузки с помощью аргументов Optional и ParamArray

Если две перегрузки процедуры имеют одинаковые сигнатуры, за исключением того, что последний параметр объявлен необязательным в одной и ParamArray в другой, компилятор разрешает вызов этой процедуры в соответствии с ближайшим совпадением. Дополнительные сведения см. в разделе Overload Resolution.

См. также раздел