visual parameter net vb.net byref byval

vb.net - parameter - ByRef vs ByVal Clarification



function visual basic (4)

Estoy empezando una clase para manejar las conexiones de cliente a un servidor TCP. Aquí está el código que he escrito hasta ahora:

Imports System.Net.Sockets Imports System.Net Public Class Client Private _Socket As Socket Public Property Socket As Socket Get Return _Socket End Get Set(ByVal value As Socket) _Socket = value End Set End Property Public Enum State RequestHeader ''''#Waiting for, or in the process of receiving, the request header ResponseHeader ''''#Sending the response header Stream ''''#Setup is complete, sending regular stream End Enum Public Sub New() End Sub Public Sub New(ByRef Socket As Socket) Me._Socket = Socket End Sub End Class

Entonces, en mi constructor sobrecargado, estoy aceptando una referencia a una instancia de un System.Net.Sockets.Socket , ¿sí?

Ahora, en mi propiedad Socket , al establecer el valor, se requiere que sea ByVal . Tengo entendido que la instancia en la memoria se copia , y esta nueva instancia se pasa al value , y mi código establece _Socket para hacer referencia a esta instancia en la memoria. ¿Sí?

Si esto es cierto, entonces no puedo ver por qué querría usar propiedades para todo lo que no sean tipos nativos. Me imagino que puede haber un gran éxito de rendimiento si se copian instancias de clase con muchos miembros. Además, para este código en particular, me imagino que una instancia de socket copiada realmente no funcionaría, pero aún no la he probado.

De todos modos, si pudiera confirmar mi comprensión o explicar las fallas en mi lógica brumosa, se lo agradecería enormemente.


Creo que estás confundiendo el concepto de referencias vs. tipos de valor y ByVal vs. ByRef . A pesar de que sus nombres son un poco engañosos, son problemas ortogonales.

ByVal en VB.NET significa que se enviará una copia del valor provisto a la función. Para los tipos de valor ( Integer , Single , etc.) esto proporcionará una copia superficial del valor. Con tipos más grandes esto puede ser ineficiente. Sin embargo, para los tipos de referencia ( String , instancias de clase) se pasa una copia de la referencia. Debido a que una copia se pasa en mutaciones al parámetro a través de = no será visible para la función de llamada.

ByRef en VB.NET significa que se enviará una referencia al valor original a la función (1). Es casi como si el valor original se utilizara directamente dentro de la función. Las operaciones como = afectarán el valor original y serán visibles inmediatamente en la función de llamada.

Socket es un tipo de referencia (clase de lectura) y, por lo tanto, pasarlo con ByVal es barato. Aunque realiza una copia, es una copia de la referencia, no una copia de la instancia.

(1) Sin embargo, esto no es 100% cierto porque VB.NET realmente admite varios tipos de ByRef en el sitio de la llamada. Para más detalles, vea la entrada del blog Los muchos casos de ByRef.


Mi entendimiento siempre ha sido que la decisión ByVal / ByRef realmente importa más para los tipos de valor (en la pila). ByVal / ByRef hace muy poca diferencia para los tipos de referencia (en el montón) A MENOS QUE ese tipo de referencia sea immutable como System.String. Para objetos mutables, no importa si pasa un objeto ByRef o ByVal, si lo modifica en el método, la función que llama verá las modificaciones.

El socket es mutable, por lo que puede pasar de la forma que desee, pero si no desea mantener las modificaciones al objeto, debe hacer una copia profunda.

Module Module1 Sub Main() Dim i As Integer = 10 Console.WriteLine("initial value of int {0}:", i) ByValInt(i) Console.WriteLine("after byval value of int {0}:", i) ByRefInt(i) Console.WriteLine("after byref value of int {0}:", i) Dim s As String = "hello" Console.WriteLine("initial value of str {0}:", s) ByValString(s) Console.WriteLine("after byval value of str {0}:", s) ByRefString(s) Console.WriteLine("after byref value of str {0}:", s) Dim sb As New System.Text.StringBuilder("hi") Console.WriteLine("initial value of string builder {0}:", sb) ByValStringBuilder(sb) Console.WriteLine("after byval value of string builder {0}:", sb) ByRefStringBuilder(sb) Console.WriteLine("after byref value of string builder {0}:", sb) Console.WriteLine("Done...") Console.ReadKey(True) End Sub Sub ByValInt(ByVal value As Integer) value += 1 End Sub Sub ByRefInt(ByRef value As Integer) value += 1 End Sub Sub ByValString(ByVal value As String) value += " world!" End Sub Sub ByRefString(ByRef value As String) value += " world!" End Sub Sub ByValStringBuilder(ByVal value As System.Text.StringBuilder) value.Append(" world!") End Sub Sub ByRefStringBuilder(ByRef value As System.Text.StringBuilder) value.Append(" world!") End Sub End Module


Piense en C, y la diferencia entre un escalar, como int, y un puntero int, y un puntero a un puntero int.

int a; int* a1 = &a; int** a2 = &a1;

Pasar un es por valor. Pasar a1 es una referencia a a; es la direccion de a. Pasar a2 es una referencia a una referencia; Lo que se pasa es la dirección de a1.

Pasar una variable de lista usando ByRef es análogo al escenario a2. Ya es una referencia. Estás pasando una referencia a una referencia. Esto significa que no solo puede cambiar el contenido de la Lista, sino que también puede cambiar el parámetro para que apunte a una Lista completamente diferente. También significa que no puede pasar un nulo literal en lugar de una instancia de Lista


Recuerda que ByVal todavía pasa referencias. La diferencia es que obtienes una copia de la referencia.

Entonces, en mi constructor sobrecargado, estoy aceptando una referencia a una instancia de un System.Net.Sockets.Socket, ¿sí?

Sí, pero lo mismo sería cierto si lo pidiera ByVal lugar. La diferencia es que con ByVal obtiene una copia de la referencia: tiene una nueva variable. Con ByRef , es la misma variable.

Tengo entendido que la instancia en la memoria está copiada

No Sólo se copia la referencia. Por lo tanto, todavía estás trabajando con la misma instancia.

Aquí hay un ejemplo de código que lo explica más claramente:

Public Class Foo Public Property Bar As String Public Sub New(ByVal Bar As String) Me.Bar = Bar End Sub End Class Public Sub RefTest(ByRef Baz As Foo) Baz.Bar = "Foo" Baz = new Foo("replaced") End Sub Public Sub ValTest(ByVal Baz As Foo) Baz.Bar = "Foo" Baz = new Foo("replaced") End Sub Dim MyFoo As New Foo("-") RefTest(MyFoo) Console.WriteLine(MyFoo.Bar) ''''# outputs replaced ValTest(MyFoo) Console.WriteLine(MyFoo.Bar) ''''# outputs Foo