質問

TCPサーバーへのクライアント接続を処理するためにクラスを始めたばかりです。これが私がこれまでに書いたコードです:

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

だから、私の過負荷のコンストラクターで、私は 参照実例System.Net.Sockets.Socket, 、 はい?

今、私に Socket プロパティ、値を設定するとき、それは ByVal. 。それは私の理解です 実例 メモリには コピー, 、 この 新しいインスタンス に渡されます value, 、そして私のコードが設定されます _Socket このインスタンスをメモリ内で参照します。はい?

これが本当なら、ネイティブタイプ以外のプロパティを使用したい理由がわかりません。多くのメンバーとクラスインスタンスをコピーすると、かなりのパフォーマンスが発生する可能性があると思います。また、特にこのコードについては、コピーされたソケットインスタンスが実際には機能しないと思いますが、まだテストしていません。

とにかく、あなたが私の理解を確認するか、私の霧の論理の欠陥を説明することができれば、私はそれを大いに感謝します。

役に立ちましたか?

解決

参照の概念と値の種類を混乱させていると思います ByVal vs。 ByRef. 。彼らの名前は少し誤解を招くものですが、彼らは直交の問題です。

ByVal VB.NETでは、提供された値のコピーが関数に送信されることを意味します。値タイプの場合(Integer, Single, 、など)これは、値の浅いコピーを提供します。より大きなタイプでは、これは非効率的です。ただし、参照タイプの場合(String, 、クラスインスタンス)参照のコピーが渡されます。コピーが変異でパラメーターに渡されているため = 呼び出し関数には見えません。

ByRef VB.NETでは、元の値への参照が関数に送信されることを意味します(1)。これは、元の値が関数内で直接使用されているようなものです。のような操作 = 元の値に影響を与え、呼び出し関数にすぐに表示されます。

Socket 参照タイプ(読み取りクラス)であるため、 ByVal 安いです。コピーを実行しますが、インスタンスのコピーではなく、リファレンスのコピーです。

(1)VB.NETは実際にCalliteでいくつかの種類のBYREFをサポートしているため、これは100%真実ではありません。詳細については、ブログエントリを参照してください Byrefの多くのケース


他のヒント

それを覚えておいてください ByVal まだ参照に合格します。 違いは、参照のコピーを取得することです。

それで、私の過負荷のコンストラクターで、私はSystem.net.sockets.socketのインスタンスへの参照を受け入れています、はい?

はい、でもあなたがそれを求めた場合も同じことが言えます ByVal 代わりは。違いはそれです ByVal 参照のコピーを取得します - 新しい変数があります。と ByRef, 、同じ変数です。

メモリ内のインスタンスがコピーされていることを理解しています

いいえ。参照のみがコピーされます。したがって、あなたはまだで働いています 同じインスタンス。

これは、それをより明確に説明するコードの例です。

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

私の理解は、バイバル/バイレフの決定が(スタック上)に実際に最も重要であるということでした。 byval/byrefは、参照タイプがある場合を除き、参照タイプ(ヒープ上)ではほとんど違いをもたらしません 不変 System.Stringのように。可変オブジェクトの場合、オブジェクトをbyrefまたはbyvalに渡すかどうかは関係ありません。メソッドを変更すると、呼び出し関数が変更が表示されます。

ソケットは可変であるため、必要な方法で渡すことができますが、オブジェクトを変更したくない場合は、自分で深いコピーを作成する必要があります。

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

Cを考えてください。また、INTやINTポインターなどのスカラーの違い、およびINTポインターへのポインターを考えてください。

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

Aを渡すことは価値によってです。 A1を渡すことは、Aへの参照です。それはaのアドレスです。 A2を渡すことは、参照への参照です。渡されるのは、A1のアドレスです。

BYREFを使用してリスト変数を渡すことは、A2シナリオに類似しています。すでに参照です。参照への参照を渡しています。それを行うことは、リストの内容を変更できるだけでなく、パラメーターを変更してまったく異なるリストを指すことができることを意味します。また、リストのインスタンスの代わりにリテラルヌルを渡すことができないことを意味します

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top