Pasar argumentos por valor y por referencia (Visual Basic)

En Visual Basic, puede pasar un argumento a un procedimiento por valor o por referencia. Esto se conoce como mecanismo de paso, y determina si el procedimiento puede modificar el elemento de programación subyacente al argumento en el código de llamada. La declaración del procedimiento determina el mecanismo de paso de cada parámetro mediante la especificación de la palabra clave ByVal o ByRef.

Distinciones

Al pasar un argumento a un procedimiento, tenga en cuenta varias distinciones diferentes que interactúan entre sí:

  • Si el elemento de programación subyacente se puede modificar o no

  • Si el propio argumento se puede modificar o no

  • Si el argumento se pasa por valor o por referencia

  • Si el tipo de datos del argumento es un tipo de valor o un tipo de referencia

Para obtener más información, vea Diferencias entre argumentos modificables y no modificables y Diferencias entre pasar un argumento por valor y por referencia.

Elección del mecanismo de paso

Debe elegir el mecanismo de paso de cada argumento cuidadosamente.

  • Protección. Al elegir entre los dos mecanismos de paso, el criterio más importante es la exposición de las variables de llamada al cambio. La ventaja de pasar un argumento ByRef es que el procedimiento puede devolver un valor al código de llamada mediante ese argumento. La ventaja de pasar un argumento ByVal es que protege a una variable frente al cambio realizado por el procedimiento.

  • Rendimiento. Aunque el mecanismo de paso puede afectar al rendimiento del código, la diferencia suele ser insignificante. Una excepción a esto es un tipo de valor pasado ByVal. En este caso, Visual Basic copia el contenido de datos completo del argumento. Por lo tanto, en el caso de un tipo de valor grande, como una estructura, puede ser más eficaz pasarlo ByRef.

    En los tipos de referencia, solo se copia el puntero a los datos (cuatro bytes en plataformas de 32 bits, ocho bytes en plataformas de 64 bits). Por lo tanto, puede pasar argumentos de tipo String u Object por valor sin afectar al rendimiento.

Determinación del mecanismo de paso

La declaración del procedimiento especifica el mecanismo de paso de cada parámetro. El código de llamada no puede invalidar un mecanismo ByVal.

Si un parámetro se declara con ByRef, el código de llamada puede forzar al mecanismo a ByVal mediante la inclusión del nombre del argumento entre paréntesis en la llamada. Para obtener más información, vea Procedimiento para forzar un elemento para que pase como un valor.

El valor predeterminado en Visual Basic es pasar argumentos por valor.

Cuándo pasar un argumento por valor

  • Si el elemento de código de llamada subyacente al argumento es un elemento no modificable, declare el parámetro correspondiente ByVal. Ningún código puede cambiar el valor de un elemento no modificable.

  • Si el elemento subyacente es modificable, pero no quiere que el procedimiento pueda cambiar su valor, declare el parámetro ByVal. Solo el código de llamada puede cambiar el valor de un elemento modificable pasado por valor.

Cuándo pasar un argumento por referencia

  • Si el procedimiento tiene una necesidad genuina de cambiar el elemento subyacente en el código de llamada, declare el parámetro ByRef correspondiente.

  • Si la ejecución correcta del código depende de que el procedimiento cambie el elemento subyacente en el código de llamada, declare el parámetro ByRef. Si lo pasa por valor o si el código de llamada invalida el mecanismo de paso ByRef mediante la inclusión del argumento entre paréntesis, la llamada al procedimiento podría generar resultados inesperados.

Ejemplo

Descripción

En el ejemplo siguiente se muestra cuándo pasar argumentos por valor y cuándo hacerlo por referencia. El procedimiento Calculate tiene un parámetro ByVal y ByRef. Dada una tasa de interés, rate, y una suma de dinero, debt, la tarea del procedimiento es calcular un nuevo valor para debt que sea el resultado de aplicar la tasa de interés al valor original de debt. Dado que debt es un parámetro ByRef, el nuevo total se refleja en el valor del argumento en el código de llamada que corresponde a debt. El parámetro rate es un parámetro ByVal, porque Calculate no debe cambiar su valor.

Código

Module Module1

    Sub Main()
        ' Two interest rates are declared, one a constant and one a 
        ' variable.
        Const highRate As Double = 12.5
        Dim lowRate = highRate * 0.6

        Dim initialDebt = 4999.99
        ' Make a copy of the original value of the debt.
        Dim debtWithInterest = initialDebt

        ' Calculate the total debt with the high interest rate applied.
        ' Argument highRate is a constant, which is appropriate for a 
        ' ByVal parameter. Argument debtWithInterest must be a variable
        ' because the procedure will change its value to the calculated
        ' total with interest applied.
        Calculate(highRate, debtWithInterest)
        ' Format the result to represent currency, and display it.
        Dim debtString = Format(debtWithInterest, "C")
        Console.WriteLine("What I owe with high interest: " & debtString)

        ' Repeat the process with lowRate. Argument lowRate is not a 
        ' constant, but the ByVal parameter protects it from accidental
        ' or intentional change by the procedure. 

        ' Set debtWithInterest back to the original value.
        debtWithInterest = initialDebt
        Calculate(lowRate, debtWithInterest)
        debtString = Format(debtWithInterest, "C")
        Console.WriteLine("What I owe with low interest:  " & debtString)
    End Sub

    ' Parameter rate is a ByVal parameter because the procedure should
    ' not change the value of the corresponding argument in the 
    ' calling code. 

    ' The calculated value of the debt parameter, however, should be
    ' reflected in the value of the corresponding argument in the 
    ' calling code. Therefore, it must be declared ByRef. 
    Sub Calculate(ByVal rate As Double, ByRef debt As Double)
        debt = debt + (debt * rate / 100)
    End Sub

End Module

Consulte también