Solucionando problemas de procedimentos (Visual Basic)
Esta página lista alguns problemas comuns que podem ocorrer ao trabalhar com procedimentos.
Retornando um tipo de matriz de um procedimento Function
Se um procedimento Function
retornar um tipo de dados de matriz, você não poderá usar o nome Function
para armazenar valores nos elementos da matriz. Se você tentar fazer isso, o compilador o interpretará como uma chamada para o Function
. O exemplo a seguir gera erros do compilador:
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
A instrução AllOnes(i) = 1
gera um erro do compilador porque parece chamar AllOnes
com um argumento do tipo de dados errado (um Integer
escalar em vez de uma matriz Integer
). A instrução Return AllOnes()
gera um erro do compilador porque parece chamar AllOnes
sem nenhum argumento.
Abordagem correta: Para poder modificar os elementos de uma matriz que deve ser retornada, defina uma matriz interna como uma variável local. O seguinte exemplo é compilado sem erro:
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
Argumento não modificado por chamada de procedimento
Se você pretende permitir que um procedimento altere um elemento de programação subjacente a um argumento no código de chamada, você precisa passá-lo por referência. Mas um procedimento pode acessar os elementos de um argumento de tipo de referência mesmo se você passá-lo por valor.
Variável Subjacente. Para permitir que o procedimento substitua o valor do próprio elemento de variável subjacente, o procedimento precisa declarar o parâmetro ByRef. Além disso, o código de chamada não deve incluir o argumento em parênteses, pois isso substituiria o mecanismo para passar argumentos
ByRef
.Elementos de tipo de referência. Se você declarar um parâmetro ByVal, o procedimento não poderá modificar o próprio elemento de variável subjacente. No entanto, se o argumento for um tipo de referência, o procedimento poderá modificar os membros do objeto ao qual ele aponta, embora não possa substituir o valor da variável. Por exemplo, se o argumento for uma variável de matriz, o procedimento não poderá atribuir uma nova matriz a ele, mas pode alterar um ou mais dos elementos dele. Os elementos alterados são refletidos na variável de matriz subjacente no código de chamada.
O exemplo a seguir mostra dois procedimentos que pegam uma variável de matriz e operam nos elementos dela. O procedimento increase
simplesmente adiciona uma a cada elemento. O procedimento replace
atribui uma nova matriz ao parâmetro a()
e adiciona uma a cada elemento. No entanto, a reatribuição não afeta a variável de matriz subjacente no código de chamada porque a()
é declarado como 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
O seguinte exemplo faz chamadas a increase
e 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)))
A primeira chamada MsgBox
exibe "Após o aumento(n): 11, 21, 31, 41". Como n
é um tipo de referência, increase
pode alterar os membros dele, mesmo que ele seja passado ByVal
.
A segunda chamada MsgBox
exibe "Após substituir(n): 11, 21, 31, 41". Como n
é passado ByVal
, replace
não pode modificar a variável n
atribuindo uma nova matriz a ela. Quando replace
cria a nova instância de matriz k
e a atribui à variável local a
, ele perde a referência a n
passada pelo código de chamada. Quando ele altera os membros de a
, apenas a matriz local k
é afetada.
Abordagem correta: Para poder modificar um elemento de variável subjacente em si, passe-o por referência. O exemplo a seguir mostra a alteração na declaração de replace
que permite substituir uma matriz por outra no código de chamada:
Public Sub replace(ByRef a() As Long)
Não é possível definir uma sobrecarga
Se você quiser definir uma versão sobrecarregada de um procedimento, deverá usar o mesmo nome, mas uma assinatura diferente. Se o compilador não puder diferenciar sua declaração de uma sobrecarga com a mesma assinatura, ele gerará um erro.
A assinatura de um procedimento é determinada pelo nome do procedimento e pela lista de parâmetros. Cada sobrecarga precisa ter o mesmo nome que todas as outras sobrecargas, mas precisa ser diferente de todas elas em pelo menos um dos outros componentes da assinatura. Para obter mais informações, consulte Sobrecarga de Procedimento.
Os seguintes itens, embora sejam pertencentes à lista de parâmetros, não são componentes da assinatura de um procedimento:
- Palavras-chave do modificador de procedimento, como
Public
,Shared
eStatic
. - Nomes de parâmetros.
- Palavras-chave do modificador de parâmetro, como
ByRef
eOptional
. - O tipo de dados do valor retornado (exceto para um operador de conversão).
Você não pode sobrecarregar um procedimento variando apenas um ou mais dos itens anteriores.
Abordagem correta: Para poder definir uma sobrecarga de procedimento, você precisa variar a assinatura. Como você precisa usar o mesmo nome, você precisa variar o número, a ordem ou os tipos de dados dos parâmetros. Em um procedimento genérico, você pode variar o número de parâmetros de tipo. Em um operador de conversão (Função CType), você pode variar o tipo de retorno.
Resolução de sobrecarga com argumentos Opcionais e ParamArray
Se você estiver sobrecarregando um procedimento com um ou mais parâmetros Opcionais ou um parâmetro ParamArray, evite duplicar qualquer uma das sobrecargas implícitas. Para obter informações, consulte Considerações sobre Procedimentos de Sobrecarga.
Chamando a versão errada de um procedimento sobrecarregado
Se um procedimento tiver várias versões sobrecarregadas, você deverá estar familiarizado com todas as listas de parâmetros e entender como o Visual Basic resolve chamadas entre as sobrecargas. Caso contrário, você poderia chamar uma sobrecarga diferente da pretendida.
Quando você tiver determinado qual sobrecarga deseja chamar, tenha cuidado para observar as seguintes regras:
- Forneça o número correto de argumentos e na ordem correta.
- Idealmente, seus argumentos devem ter exatamente os mesmos tipos de dados que os parâmetros correspondentes. De qualquer forma, o tipo de dados de cada argumento precisa ser ampliado para o do parâmetro correspondente dele. Isso é verdadeiro mesmo com a Instrução Option Strict definida como
Off
. Se uma sobrecarga exigir qualquer conversão de restrição da sua lista de argumentos, essa sobrecarga não será qualificada para ser chamada. - Se você fornecer argumentos que exigem expansão, faça com que os tipos de dados deles sejam o mais próximos possível dos tipos de dados de parâmetro correspondentes. Se duas ou mais sobrecargas aceitarem seus tipos de dados de argumento, o compilador resolverá sua chamada para a sobrecarga que exige a menor quantidade de expansão.
Você pode reduzir a chance de incompatibilidades de tipo de dados usando a palavra-chave de conversão da Função CType ao preparar seus argumentos.
Falha na resolução da sobrecarga
Quando você chama um procedimento sobrecarregado, o compilador tenta eliminar todas, exceto uma das sobrecargas. Se ele tiver êxito, ele resolverá a chamada para essa sobrecarga. Se eliminar todas as sobrecargas ou se não puder reduzir as sobrecargas qualificadas para um único candidato, ele gerará um erro.
O seguinte exemplo ilustra o processo de resolução de sobrecarga:
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)
Na primeira chamada, o compilador elimina a primeira sobrecarga porque o tipo do primeiro argumento (Short
) se restringe ao tipo do parâmetro correspondente (Byte
). Em seguida, ele elimina a terceira sobrecarga porque cada tipo de argumento na segunda sobrecarga (Short
e Single
) é expandido para o tipo correspondente na terceira sobrecarga (Integer
e Single
). A segunda sobrecarga requer menos expansão, portanto, o compilador a usa para a chamada.
Na segunda chamada, o compilador não pode eliminar nenhuma das sobrecargas com base na restrição. Ele elimina a terceira sobrecarga pelo mesmo motivo que na primeira chamada, pois pode chamar a segunda sobrecarga com menos expansão dos tipos de argumento. No entanto, o compilador não pode resolver entre a primeira e a segunda sobrecargas. Cada um tem um tipo de parâmetro definido que é expandido para o tipo correspondente no outro (Byte
para Short
, mas Single
para Double
). Portanto, o compilador gera um erro de resolução de sobrecarga.
Abordagem correta: Para poder chamar um procedimento sobrecarregado sem ambiguidade, use a Função CType para corresponder os tipos de dados de argumento aos tipos de parâmetro. O exemplo a seguir mostra uma chamada para z
que força a resolução à segunda sobrecarga.
Call z(CType(p, Short), CType(q, Single))
Resolução de sobrecarga com argumentos Opcionais e ParamArray
Se duas sobrecargas de um procedimento tiverem assinaturas idênticas, exceto que o último parâmetro será declarado Opcional em um e ParamArray no outro, o compilador resolverá uma chamada para esse procedimento de acordo com a correspondência mais próxima. Para obter mais informações, consulte Resolução de Sobrecarga.