Solución de problemas de Procedimientos (Visual Basic)

En esta página se indican algunos problemas comunes que pueden producirse al trabajar con procedimientos.

Devolver un tipo de matriz desde un procedimiento de función

Si un procedimiento devuelve un Function tipo de datos de matriz, no puedes usar el Function nombre para almacenar valores en los elementos de la matriz. Si intentas hacerlo, el compilador lo interpreta como una llamada a Function. El ejemplo siguiente genera errores del 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

La instrucción AllOnes(i) = 1 genera un error del compilador porque parece llamar AllOnes a con un argumento del tipo de datos incorrecto (un escalar Integer en lugar de una Integer matriz). La instrucción Return AllOnes() genera un error del compilador porque parece llamar AllOnes a sin ningún argumento.

Enfoque correcto: Para poder modificar los elementos de una matriz que se va a devolver, defina una matriz interna como una variable local. En el ejemplo siguiente se compila sin errores:

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 no modificado por llamada a procedimiento

Si tienes previsto permitir que un procedimiento cambie un elemento de programación subyacente a un argumento en el código que realiza la llamada, debes pasarlo por referencia. Pero un procedimiento puede tener acceso a los elementos de un argumento de tipo de referencia incluso si se pasa por valor.

  • Variable subyacente. Para permitir que el procedimiento reemplace el valor del propio elemento de variable subyacente, el procedimiento debe declarar el parámetro ByRef. Además, el código de llamada no debe incluir el argumento entre paréntesis, ya que esto invalidaría el ByRef mecanismo de paso.

  • Elementos de tipo de referencia. Si declaras un parámetro ByVal, el procedimiento no puede modificar el propio elemento de variable subyacente. Sin embargo, si el argumento es un tipo de referencia, el procedimiento puede modificar los miembros del objeto al que apunta, aunque no pueda reemplazar el valor de la variable. Por ejemplo, si el argumento es una variable de matriz, el procedimiento no puede asignarle una nueva matriz, pero puede cambiar uno o varios de sus elementos. Los elementos modificados se reflejan en la variable de matriz subyacente en el código que llama.

En el ejemplo siguiente define dos procedimientos que toman una variable de matriz por valor y operan en sus elementos. El increase procedimiento simplemente agrega uno a cada elemento. El replace procedimiento asigna una nueva matriz al parámetro a() y, a continuación, agrega una a cada elemento. Sin embargo, la reasignación no afecta a la variable de matriz subyacente en el código que realiza la llamada porque a() se declaraByVal.

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

En el ejemplo siguiente se realizan llamadas a increase y 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)))

La primera MsgBox llamada muestra «After increase(n): 11, 21, 31, 41». Dado n que es un tipo de referencia, increase puede cambiar sus miembros, aunque se pase ByVal.

La segunda MsgBox llamada muestra «After replace(n): 11, 21, 31, 41». Dado que n se pasa ByVal, replace no se puede modificar la variable n mediante la asignación de una nueva matriz a ella. Cuando replace crea la nueva instancia k de matriz y la asigna a la variable alocal, pierde la referencia a n pasada por el código que realiza la llamada. Cuando aumenta los miembros de a, solo se ve afectada la matriz k local.

Enfoque correcto: Para poder modificar un propio elemento de variable subyacente, páselo por referencia. En el ejemplo siguiente se muestra el cambio en la declaración de replace que permite reemplazar una matriz por otra en el código de llamada:

Public Sub replace(ByRef a() As Long)

No se puede definir una sobrecarga

Si deseas definir una versión sobrecargada de un procedimiento, debes usar el mismo nombre, pero una firma diferente. Si el compilador no puede diferenciar la declaración de una sobrecarga con la misma firma, genera un error.

La firma de un procedimiento viene determinada por el nombre del procedimiento y la lista de parámetros. Cada sobrecarga debe tener el mismo nombre que todas las demás sobrecargas, pero debe diferir de todas ellas en al menos uno de los demás componentes de la firma. Para obtener más información, consulta Procedure Overloading.

Los siguientes elementos, aunque pertenecen a la lista de parámetros, no son componentes de la firma de un procedimiento:

  • Palabras clave de modificador del procedimiento, como Public, Shared y Static.
  • Nombres de parámetro.
  • Palabras clave del modificador de parámetros, como ByRef y Optional.
  • El tipo de datos del valor devuelto (excepto para un operador de conversión).

No se puede sobrecargar un procedimiento variando solo uno o varios de los elementos anteriores.

Enfoque correcto: Para poder definir una sobrecarga de procedimiento, debe variar la firma. Dado que debes usar el mismo nombre, debes variar el número, el orden o los tipos de datos de los parámetros. En un procedimiento genérico, puedes variar el número de parámetros de tipo. En un operador de conversión (Función CType), puedes variar el tipo de valor devuelto.

Resolución de sobrecarga con argumentos Optional y ParamArray

Si estás sobrecargando un procedimiento con uno o varios parámetros Optional o un parámetro ParamArray, debes evitar duplicar cualquiera de las sobrecargas implícitas. Para obtener información, consulta Consideraciones sobre procedimientos de sobrecarga.

Llamada a la versión incorrecta de un procedimiento sobrecargado

Si un procedimiento tiene varias versiones sobrecargadas, deberías estar familiarizado con todas sus listas de parámetros y comprender cómo Visual Basic resuelve las llamadas entre las sobrecargas. De lo contrario, podrías llamar a una sobrecarga distinta de la prevista.

Cuando hayas determinado qué sobrecarga desea llamar, ten cuidado de observar las reglas siguientes:

  • Proporciona el número correcto de argumentos y en el orden correcto.
  • Lo ideal es que tus argumentos tengan exactamente los mismos tipos de datos que los parámetros correspondientes. En cualquier caso, el tipo de datos de cada argumento debe ampliarse al de su parámetro correspondiente. Esto es cierto incluso con la instrucción Option Strict establecida en Off. Si una sobrecarga requiere una conversión de restricción de la lista de argumentos, esa sobrecarga no es apta para llamarse.
  • Si proporcionas argumentos que requieren ampliación, haz que tus tipos de datos se acerquen lo más posible a los tipos de datos de parámetro correspondientes. Si dos o más sobrecargas aceptan los tipos de datos de argumento, el compilador resuelve la llamada a la sobrecarga que llama a la menor cantidad de ampliación.

Puedes reducir la posibilidad de que los tipos de datos no coincidan mediante la palabra clave de conversión de función CType al preparar los argumentos.

Error en la resolución de sobrecarga

Cuando se llama a un procedimiento sobrecargado, el compilador intenta eliminar todas las sobrecargas, excepto una de las sobrecargas. Si se ejecuta correctamente, resuelve la llamada a esa sobrecarga. Si eliminas todas las sobrecargas, o si no puedes reducir las sobrecargas aptas a un único candidato, genera un error.

En el ejemplo siguiente se muestra el proceso de resolución 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)

En la primera llamada, el compilador elimina la primera sobrecarga porque el tipo del primer argumento (Short) se limita al tipo del parámetro correspondiente (Byte). A continuación, elimina la tercera sobrecarga porque cada tipo de argumento de la segunda sobrecarga (Short y Single) amplía al tipo correspondiente en la tercera sobrecarga (Integer y Single). La segunda sobrecarga requiere menos ampliación, por lo que el compilador lo usa para la llamada.

En la segunda llamada, el compilador no puede eliminar ninguna de las sobrecargas en función de la restricción. Elimina la tercera sobrecarga por la misma razón que en la primera llamada, ya que puede llamar a la segunda sobrecarga con menos ampliación de los tipos de argumento. Sin embargo, el compilador no se puede resolver entre las sobrecargas primera y segunda. Cada tiene un tipo de parámetro definido que amplía al tipo correspondiente en el otro (Byte a Short, pero Single a Double). Por lo tanto, el compilador genera un error de resolución de sobrecarga.

Enfoque correcto: Para poder llamar a un procedimiento sobrecargado sin ambigüedad, use la función CType para hacer coincidir los tipos de datos de argumento con los tipos de parámetro. En el ejemplo siguiente se muestra una llamada a z que fuerza la resolución a la segunda sobrecarga.

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

Resolución de sobrecarga con argumentos Optional y ParamArray

Si dos sobrecargas de un procedimiento tienen firmas idénticas, salvo que el último parámetro se declara Opcional en uno y ParamArray en el otro, el compilador resuelve una llamada a ese procedimiento según la coincidencia más cercana. Para obtener más información, consulta Overload Resolution.

Consulte también