Domanda

Sono appena agli inizi su una classe per gestire le connessioni client a un server TCP. Ecco il codice che ho scritto finora:

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

Quindi, il mio costruttore di sovraccarico, sto accettando un di riferimento per un istanza di un System.Net.Sockets.Socket, sì?

Ora, sulla mia proprietà Socket, quando si imposta il valore, è necessario per essere ByVal. E 'la mia comprensione che il istanza in memoria è copiato , e questo nuova istanza è passato a value, e il mio set di codici _Socket fare riferimento a queste esempio in memoria. Sì?

Se questo è vero, allora non vedo perché dovrei usare le proprietà per qualsiasi cosa, ma tipi nativi. Mi immagino non ci può essere un bel colpo di prestazioni se la copia di istanze di classe con un sacco di membri. Inoltre, per questo codice, in particolare, mi immagino un'istanza presa copiato non sarebbe davvero il lavoro, ma non ho ancora testato ancora.

In ogni caso, se si potesse o confermare la mia comprensione, o spiegare i difetti nella mia logica di nebbia, sarei molto grato.

È stato utile?

Soluzione

credo che tu stia confondendo il concetto di riferimenti vs. tipi di valore e ByVal vs. ByRef. Anche se i loro nomi sono un po 'fuorviante, sono problemi ortogonali.

ByVal nei mezzi VB.NET che una copia del valore fornito verrà inviato alla funzione. Per i tipi di valore (Integer, Single, ecc) questo fornirà una copia del valore. Con i tipi più grandi questo può essere inefficiente. Per i tipi di riferimento anche se (String, istanze di classe) viene passata una copia del riferimento. Perché una copia viene passato mutazioni al parametro tramite = non sarà visibile alla funzione di chiamata.

ByRef nei mezzi VB.NET che un riferimento al valore originale verrà inviato alla funzione (1). E 'quasi come il valore originale viene utilizzato direttamente all'interno della funzione. Operazioni come = influenzerà il valore originale e immediatamente visibile nella funzione di chiamata.

Socket è un tipo di riferimento (classe lettura) e quindi passa con ByVal è economico. Anche se lo fa eseguire una copia è una copia del riferimento, non una copia dell'istanza.

(1) Questo non è vero al 100%, però, perché VB.NET supporta in realtà diversi tipi di ByRef al callsite. Per maggiori dettagli, vedere la voce del blog I molti casi di ByRef


Altri suggerimenti

Ricordate che ByVal passa ancora riferimenti. La differenza è che si ottiene una copia del riferimento.

  

Quindi, il mio costruttore di sovraccarico, sto accettando un riferimento a un'istanza di uno System.Net.Sockets.Socket, sì?

Sì, ma lo stesso sarebbe vero se l'è cercata ByVal invece. La differenza è che con ByVal si ottiene una copia del riferimento - avete nuova variabile. Con ByRef, è la stessa variabile.

  

E 'la mia comprensione che l'istanza in memoria viene copiato

No. viene copiato solo il riferimento. Pertanto, si sta ancora lavorando con il stessa istanza.

Ecco un esempio di codice che spiega più chiaramente:

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

La mia comprensione è sempre stata che l'/ ByRef decisione ByVal davvero conta di più per i tipi di valore (sullo stack). ByVal / ByRef rende molto poca differenza a tutti per tipi di riferimento (sull'heap) a meno che tipo di riferimento è immutabili come System.String. Per gli oggetti mutabili, non importa se si passa un oggetto ByRef o ByVal, chi lo modifica nel metodo della funzione di chiamata vedrà le modifiche.

Socket è mutevole, in modo da poter passare in tutti i modi che vuoi, ma se non si desidera mantenere le modifiche all'oggetto è necessario fare una profonda da soli copia.

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

Pensate a C, e la differenza tra uno scalare, come int e un puntatore a int e un puntatore a un puntatore a int.

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

Il passaggio a è per valore. Passando a1 è un riferimento ad una; è l'indirizzo di un. Passando a2 è un riferimento ad un riferimento; ciò che viene passato è l'indirizzo della A1.

Passaggio di una variabile di lista utilizzando ByRef è analogo allo scenario a2. È già un riferimento. Si passa un riferimento a un riferimento. Fare questo significa che non solo si può modificare il contenuto della lista, è possibile in grado di modificare il parametro a punto da un elenco di completamente diverso. Significa, inoltre, non è possibile passare un null letterali invece di un'istanza di List

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top