Pregunta

estoy empezando en una clase para controlar 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

Por lo tanto, en mi constructor sobrecargado, estoy aceptando un referencia para un ejemplo de un System.Net.Sockets.Socket, sí?

Ahora, en mi propiedad Socket, al establecer el valor, se requiere ser ByVal. Es mi entendimiento de que el ejemplo en la memoria es copiados , y esto nueva instancia se pasa a value, y mis conjuntos de códigos _Socket hacer referencia a este ejemplo en la memoria. Sí?

Si esto es cierto, entonces no puedo ver por qué me gustaría utilizar las propiedades para cualquier cosa menos tipos nativos. Me imagino que no puede haber un gran impacto en el rendimiento si la copia de instancias de la clase con una gran cantidad de miembros. Además, para este código en particular, me imagino una instancia de toma de copiado no sería realmente el trabajo, pero no he probado todavía.

De todos modos, si se puede confirmar ya sea mi entendimiento, o explicar los defectos en mi lógica de niebla, que sería de gran aprecio.

¿Fue útil?

Solución

Creo que estás confundiendo el concepto de referencias frente a los tipos de valor y ByVal vs ByRef. A pesar de que sus nombres están engañando un poco, son cuestiones ortogonales.

ByVal en medios VB.NET que una copia del valor proporcionado se enviará 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. Para los tipos de referencia, aunque (String, instancias de clases) se pasa una copia de la referencia. Debido a que una copia se pasa en el parámetro mutaciones a través de = no será visible para la función de llamada.

ByRef en medios VB.NET que una referencia al valor original se enviará a la función (1). Es casi como el valor original se utiliza directamente en la función. Operaciones como = afectará el valor original y efectivo de forma inmediata en la función de llamada.

Socket es un tipo de referencia (clase leer) y por lo tanto pasa con ByVal es barato. A pesar de que hace realizar una copia es una copia de la referencia, no una copia de la instancia.

(1) Esto no es 100% verdad, porque aunque en realidad VB.NET es compatible con varios tipos de ByRef en el callsite. Para más detalles, consulte la entrada de blog Los numerosos casos de ByRef


Otros consejos

Recuerde que ByVal todavía pasa referencias. La diferencia es que se obtiene una copia de la referencia.

Por lo tanto, 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 usted pidió que ByVal lugar. La diferencia es que con ByVal de obtener una copia de la referencia - usted tiene nueva variable. Con ByRef, es la misma variable.

Es mi entendimiento de que la instancia en la memoria se copia

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

Aquí hay un ejemplo de código que lo explica con mayor claridad:

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

Mi opinión siempre ha sido que el ByVal / ByRef decisión realmente es lo más importante para este tipo de valor (en la pila). ByVal / ByRef hace muy poca diferencia en absoluto para los tipos de referencia (en el montón) a menos que ese tipo de referencia es inmutable como System.String. Para los objetos mutables, no importa si se pasa un objeto ByRef o ByVal, si lo modifica en el método de la función de llamar a ver las modificaciones.

Socket es mutable, lo que puede pasar cualquier manera que desee, pero si usted no desea conservar las modificaciones al objeto que necesita para hacer una copia profunda usted mismo.

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

Think de 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;

Pasando a es por valor. a1 Pasando es una referencia a una; es la dirección de una. a2 de aprobación es una referencia a una referencia; lo que se pasa es la dirección de a1.

Al pasar una variable de lista usando ByRef es análogo al escenario A2. Ya es una referencia. Está pasando una referencia a una referencia. Hacer eso significa que no sólo se puede cambiar el contenido de la lista, puede puede cambiar el parámetro a punto a una lista totalmente diferente. También significa que no se puede pasar un nulo literal en lugar de una instancia de List

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top