22

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がメモリ内のこのインスタンスを参照するように設定されていることを理解しています。はい?

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

とにかく、私の理解を確認するか、私の霧の論理の欠陥を説明していただければ幸いです。

4

4 に答える 4

54

ByVal参照と値型、および . の概念を混同していると思いますByRef。それらの名前は少し誤解を招くものですが、直交する問題です。

ByValVB.NET では、提供された値のコピーが関数に送信されることを意味します。値の型 ( IntegerSingleなど) の場合、これは値の浅いコピーを提供します。より大きな型では、これは非効率になる可能性があります。ただし、参照型 ( String、クラス インスタンス) の場合、参照のコピーが渡されます。コピーはミューテーションでパラメーターに渡される=ため、呼び出し元の関数には表示されません。

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

Socket参照型(読み取りクラス)であるため、それを渡すのByValは安価です。コピーを実行しますが、それは参照のコピーであり、インスタンスのコピーではありません。

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


于 2010-12-08T00:45:58.207 に答える
14

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
于 2010-12-08T01:20:10.487 に答える
2

私の理解では、ByVal/ByRef の決定は、(スタック上の) 値の型にとって本当に重要であるということです。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
于 2010-12-08T01:31:46.243 に答える