我只是从课程开始,以处理与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 在内存中引用此实例。是的?

如果这是真的,那么我看不明白为什么我要使用本机类型以外的任何东西使用属性。我想,如果与许多成员复制课堂实例,可能会有很大的打击。另外,特别是对于此代码,我想像复制的插座实例无法真正起作用,但我尚未测试。

无论如何,如果您可以确认我的理解,也可以解释我的雾gy逻辑中的缺陷,我将非常感谢。

有帮助吗?

解决方案

我认为您正在混淆参考概念与价值类型和 ByVal VS. ByRef. 。即使他们的名字有些误导,它们还是正交的问题。

ByVal 在vb.net中,意味着提供值的副本将发送到该函数。对于价值类型(Integer, Single, ,等等。)这将提供值的浅副本。对于较大的类型,这可能是效率降低的。但是对于参考类型(String, ,课堂实例)传递了参考的副本。因为副本以突变传递到参数通过 = 通话功能看不到。

ByRef 在vb.net中,意味着对原始值的引用将发送到函数(1)。几乎就像原始值直接在功能中使用。类似的操作 = 将影响原始值,并在调用功能中立即可见。

Socket 是参考类型(阅读类),因此将其传递给 ByVal 很便宜。即使它确实执行了副本,也是引用的副本,而不是实例的副本。

(1)这不是100%正确的,因为VB.NET实际上在召唤下支持几种BYREF。有关更多详细信息,请参阅博客条目 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决策对价值类型(在堆栈上)确实至关重要。 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的引用;它是一个地址。通过A2是对参考的参考;通过的是A1的地址。

使用BYREF传递列表变量类似于A2方案。它已经是参考。您正在传递对参考的参考。这样做意味着您不仅可以更改列表的内容,还可以更改参数以指向完全不同的列表。这也意味着您不能通过字面的空而不是列表的实例

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top