Buscar..


Introducción

El código que se compila todavía puede tener errores, en tiempo de ejecución. Este tema enumera los más comunes, sus causas y cómo evitarlos.

Error en tiempo de ejecución '3': Devolución sin GoSub

Código incorrecto

Sub DoSomething()
    GoSub DoThis
DoThis:
    Debug.Print "Hi!"
    Return
End Sub

¿Por qué no funciona esto?

La ejecución ingresa al procedimiento DoSomething , salta a la etiqueta DoThis , imprime "¡Hola!" a la salida de depuración, vuelve a las instrucciones inmediatamente después de la llamada GoSub , imprime "¡Hola!" de nuevo, y luego encuentra una declaración de Return , pero no hay a dónde regresar ahora, porque no llegamos aquí con una declaración de GoSub .

Código correcto

Sub DoSomething()
    GoSub DoThis
    Exit Sub
DoThis:
    Debug.Print "Hi!"
    Return
End Sub

¿Por qué funciona esto?

Al introducir una instrucción Exit Sub antes de la DoThis línea DoThis , hemos separado la subrutina DoThis del resto del cuerpo del procedimiento: la única forma de ejecutar la subrutina DoThis es a través del salto GoSub .

Otras notas

GoSub / Return está en desuso, y debe evitarse en favor de las llamadas a procedimientos reales. Un procedimiento no debe contener subrutinas, excepto los controladores de errores.

Esto es muy similar al error en tiempo de ejecución '20': Reanudar sin error ; en ambas situaciones, la solución es garantizar que la ruta de ejecución normal no pueda ingresar a una subrutina (identificada por una etiqueta de línea) sin un salto explícito (asumiendo que On Error GoTo se considera un salto explícito ).

Error en tiempo de ejecución '6': Desbordamiento

código incorrecto

Sub DoSomething()
    Dim row As Integer
    For row = 1 To 100000
        'do stuff
    Next
End Sub

¿Por qué no funciona esto?

El tipo de datos Integer es un entero con signo de 16 bits con un valor máximo de 32,767; asignarlo a algo más grande que eso desbordará el tipo y generará este error.

Código correcto

Sub DoSomething()
    Dim row As Long
    For row = 1 To 100000
        'do stuff
    Next
End Sub

¿Por qué funciona esto?

Al usar un entero Long (32 bits) en su lugar, ahora podemos hacer un bucle que itere más de 32,767 veces sin desbordar el tipo de variable del contador.

Otras notas

Consulte Tipos de datos y límites para obtener más información.

Error en tiempo de ejecución '9': Subíndice fuera de rango

código incorrecto

Sub DoSomething()
    Dim foo(1 To 10)
    Dim i As Long
    For i = 1 To 100
        foo(i) = i
    Next
End Sub

¿Por qué no funciona esto?

foo es una matriz que contiene 10 elementos. Cuando el contador de bucle i alcanza un valor de 11, foo(i) está fuera de rango . Este error se produce siempre que se accede a una matriz o colección con un índice que no existe en esa matriz o colección.

Código correcto

Sub DoSomething()
    Dim foo(1 To 10)
    Dim i As Long
    For i = LBound(foo) To UBound(foo)
        foo(i) = i
    Next
End Sub

¿Por qué funciona esto?

Use las funciones LBound y UBound para determinar los límites inferior y superior de una matriz, respectivamente.

Otras notas

Cuando el índice es una cadena, por ejemplo, ThisWorkbook.Worksheets("I don't exist") , este error significa que el nombre proporcionado no existe en la colección consultada.

Sin embargo, el error real es específico de la implementación; Collection generará el error de tiempo de ejecución 5 "Llamada o argumento de procedimiento no válido" en su lugar:

Sub RaisesRunTimeError5()
    Dim foo As New Collection
    foo.Add "foo", "foo"
    Debug.Print foo("bar")
End Sub

Error en tiempo de ejecución '13': No coincide el tipo

código incorrecto

Public Sub DoSomething()
    DoSomethingElse "42?"
End Sub

Private Sub DoSomethingElse(foo As Date)
'    Debug.Print MonthName(Month(foo))
End Sub

¿Por qué no funciona esto?

VBA está realmente tratando de convertir el "42?" argumento en un valor de Date . Cuando falla, la llamada a DoSomethingElse no se puede ejecutar, porque VBA no sabe qué fecha pasar, por lo que aumenta el tipo de error de tiempo de ejecución 13, porque el tipo de argumento no coincide con el tipo esperado (y puede Tampoco se convertirá implícitamente).

Código correcto

Public Sub DoSomething()
    DoSomethingElse Now
End Sub

Private Sub DoSomethingElse(foo As Date)
'    Debug.Print MonthName(Month(foo))
End Sub

¿Por qué funciona esto?

Al pasar un argumento de Date a un procedimiento que espera un parámetro de Date , la llamada puede tener éxito.

Error en tiempo de ejecución '91': variable de objeto o variable de bloque no establecida

código incorrecto

Sub DoSomething()
    Dim foo As Collection
    With foo
        .Add "ABC"
        .Add "XYZ"
    End With
End Sub

¿Por qué no funciona esto?

Las variables de objeto contienen una referencia y las referencias deben establecerse con la palabra clave Set . Este error se produce cuando se realiza una llamada de miembro en un objeto cuya referencia es Nothing . En este caso, foo es una referencia de Collection , pero no está inicializada, por lo que la referencia no contiene Nothing , y no podemos llamar a .Add en Nothing .

Código correcto

Sub DoSomething()
    Dim foo As Collection
    Set foo = New Collection
    With foo
        .Add "ABC"
        .Add "XYZ"
    End With
End Sub

¿Por qué funciona esto?

Al asignar a la variable de objeto una referencia válida utilizando la palabra clave Set , las llamadas .Add se .Add correctamente.

Otras notas

A menudo, una función o propiedad puede devolver una referencia de objeto; un ejemplo común es el método Range.Find de Excel, que devuelve un objeto Range :

Dim resultRow As Long
resultRow = SomeSheet.Cells.Find("Something").Row

Sin embargo, la función puede devolver Nothing (si no se encuentra el término de búsqueda), por lo que es probable que la llamada al miembro .Row encadenado falle.

Antes de llamar a los miembros del objeto, verifique que la referencia esté establecida con una condición If Not xxxx Is Nothing :

Dim result As Range
Set result = SomeSheet.Cells.Find("Something")

Dim resultRow As Long
If Not result Is Nothing Then resultRow = result.Row

Error en tiempo de ejecución '20': Reanudar sin error

código incorrecto

Sub DoSomething()
    On Error GoTo CleanFail
    DoSomethingElse

CleanFail:
    Debug.Print Err.Number
    Resume Next
End Sub

¿Por qué no funciona esto?

Si el procedimiento DoSomethingElse genera un error, la ejecución salta a la CleanFail línea CleanFail , imprime el número de error y la instrucción Resume Next vuelve a la instrucción que sigue inmediatamente a la línea donde ocurrió el error, que en este caso es Debug.Print instrucción: la subrutina de manejo de errores se ejecuta sin un contexto de error, y cuando se alcanza la instrucción Resume Next , se genera el error 20 en tiempo de ejecución porque no hay ningún lugar para reanudar.

Código correcto

Sub DoSomething()
    On Error GoTo CleanFail
    DoSomethingElse

    Exit Sub    
CleanFail:
    Debug.Print Err.Number
    Resume Next
End Sub

¿Por qué funciona esto?

Al introducir una instrucción Exit Sub antes de la CleanFail línea CleanFail , hemos segregado la subrutina de manejo de errores CleanFail del resto del cuerpo del procedimiento: la única forma de ejecutar la subrutina de manejo de errores es a través de un salto On Error ; por lo tanto, ninguna ruta de ejecución llega a la instrucción Resume fuera de un contexto de error, lo que evita el error 20 en tiempo de ejecución.

Otras notas

Esto es muy similar al error en tiempo de ejecución '3': Devolución sin GoSub ; en ambas situaciones, la solución es garantizar que la ruta de ejecución normal no pueda ingresar a una subrutina (identificada por una etiqueta de línea) sin un salto explícito (asumiendo que On Error GoTo se considera un salto explícito ).



Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow