Pregunta

¿Cuáles son las cosas a tener en cuenta al elegir entre ByRef y ByVal?

Entiendo la diferencia entre los dos, pero no entiendo completamente si ByRef ahorra recursos o si incluso debemos preocuparnos por eso en el entorno .Net.

¿Cómo decide entre los dos si la funcionalidad no importa en una situación?

¿Fue útil?

Solución

Hay mucha desinformación sobre esto. Lo principal es que comprenda la diferencia entre los tipos de valor y los tipos de referencia , y la diferencia entre pasar por valor y pasar por referencia .

Casi siempre quieres pasar por valor. Pasar por referencia casi siempre es para "Quiero devolver más de un resultado, y no solo agregando cosas a una lista que se pasa". El ejemplo clásico de un método que usa la referencia de paso es Int32. TryParse donde el valor de retorno es un éxito / error, y el valor analizado se devuelve " por un parámetro de salida.

Otros consejos

El valor predeterminado es byValue para TODOS los tipos, pero es importante comprender qué significan las dos opciones para un " tipo de referencia " (una clase) en oposición a un tipo de valor. (estructuras).

Para un tipo de referencia, si declara una variable de tipo de referencia en un método, esa variable es una ubicación de memoria en el marco de la pila del método. No está en el montón. Cuando inicializa esa variable (usando nuevo o una fábrica, lo que sea), entonces ha creado un objeto real en el montón, y la dirección de ese objeto se almacena en la variable de referencia declarada en el marco de la pila de métodos.

Cuando pasa un tipo de referencia a otro método por Val, está creando una copia de la dirección almacenada en la pila de métodos de llamada y pasando la copia de ese valor (la dirección del puntero) al método llamado, donde se almacena en una nueva ranura de memoria en la pila de métodos llamados. Dentro del método llamado, la nueva variable clonada apunta directamente al mismo objeto en el montón. Por lo tanto, usarlo puede cambiar las propiedades del mismo objeto. Pero no puede cambiar a qué objeto de montón apunta la variable de referencia original (en la pila de métodos de llamada). Si, en el método llamado escribo

  myVar = new object();

La variable original en el método de llamada no habrá cambiado para apuntar a un nuevo objeto.

Si paso un tipo de referencia por Ref, otoh, estoy pasando un puntero a la variable declarada en la pila de métodos de llamada (que contiene un puntero al objeto en el montón) Por lo tanto, es un puntero a un puntero al objeto . Apunta a la ubicación de memoria en la pila de métodos de llamada, que apunta al objeto en el montón.
Entonces, si cambio el valor de la variable en el método llamado, configurándolo en un nuevo objeto (), como se indicó anteriormente, ya que es una "referencia". a la variable en el método de llamada, en realidad estoy cambiando a qué objeto apunta la variable en el método de llamada. Entonces, después de que el método llamado regrese, la variable en el método de llamada ya no apuntará al mismo objeto original en el montón.

ByVal debería ser su " predeterminado " ;. Úselo a menos que tenga una razón específica para usar ByRef

Pasar un objeto ByVal en .net no hace una copia del objeto y no consume más recursos que ByRef. Todavía se pasa un puntero a la función. El tiempo de ejecución solo garantiza que no pueda modificar el puntero en su función y devolverle un valor diferente. Todavía puede realizar cambios en los valores dentro del objeto y verá esos cambios fuera de la función. Es por eso que ByRef se usa tan raramente. Solo es necesario cuando desea que una función cambie el objeto real que está volviendo; de ahí un parámetro de salida.

Use " ByRef " solo si el parámetro es " salida " parámetro. De lo contrario, use " ByVal " ;. Usando " ByRef " en parámetros que explícitamente no deberían devolver valores es peligroso y puede generar errores fácilmente.

Yo diría que ByRef nunca debe usarse, que es una mala práctica. Lo aplicaría incluso a su caso de uso típico de permitir que una función devuelva múltiples valores (a través de parámetros ByRef). Sería mejor para la función devolver una respuesta estructurada que incluya esos valores de retorno múltiples. Es más claro y más obvio si una función solo devuelve valores a través de su declaración de retorno.

Marcar ciertos argumentos como ByRef muestra al usuario de su función que la variable asignada a ese argumento ** se modificará. ****

Si usa ByRef para todos los argumentos, no habrá forma de saber qué variables son modificadas por la función y cuáles son leídas por ella. (¡aparte de mirar dentro de la fuente de función!)

Según Microsoft, elegir ByVal o ByRef puede afectar el rendimiento para valores suficientemente grandes (consulte Pasar argumentos por valor y por referencia (Visual Basic) ):

  

Rendimiento. Aunque el mecanismo de pase puede afectar el rendimiento   de su 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 todo el contenido de datos del argumento. Por lo tanto, para un   tipo de gran valor como una estructura, puede ser más eficiente pasar   es ByRef.

[énfasis agregado].

Sub last_column_process()
Dim last_column As Integer

last_column = 234
MsgBox last_column

trying_byref x:=last_column
MsgBox last_column

trying_byval v:=last_column
MsgBox last_column

End Sub

Sub trying_byref(ByRef x)
x = 345
End Sub

Sub trying_byval(ByRef v)
v = 555
End Sub

Mucha confusión intentaré simplificar. Básicamente tienes 4 opciones:

  1. Pase un tipo de valor byVal
  2. Pase un tipo de valor porRef
  3. Pase un objeto porVal
  4. Pase un objeto porRef

Algunas personas dicen que nunca debe usar byRef. Si bien son técnicamente correctos, una cosa es segura. Debería NUNCA usar la palabra nunca . Si está diseñando un sistema desde cero, entonces byRef debe evitarse a toda costa. Su uso expone un defecto de diseño. Sin embargo, trabajar en un sistema existente puede no proporcionar tanta flexibilidad para implementar un buen diseño. A veces debes hacer confesiones, es decir, usar byRef. Por ejemplo, si puede obtener una solución en 2 días usando byRef, entonces eso puede ser preferible a reinventar la rueda y tomar una semana para obtener la misma solución solo para evitar usar byRef.

Resumen:

  1. Uso de byVal en un tipo de valor: pasa un valor a una función. Esta es la forma preferida de funciones de diseño.
  2. Uso de byRef en un tipo de valor: útil para devolver más de un valor de una función. Si tu están creando una función que necesita devolver más de un valor a un sistema existente, esto puede ser mejor que crear un objeto (y establecer propiedades y desechar) solo para una función.
  3. Uso de byVal en un objeto: pasa un puntero de un objeto a una función. La función puede modificar el objeto.
  4. Uso de byRef en un objeto: pasa un puntero a un puntero de un objeto a una función. Permite cambiando el objeto al que apunta la persona que llama. Esto puede causar algunos Es difícil encontrar errores y no se me ocurre ninguna buena razón para usarlo. No significa que no haya uno, pero si los hay, son pocos y lejos.
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top