首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ByRef对ByVal的澄清

ByRef对ByVal的澄清
EN

Stack Overflow用户
提问于 2010-12-08 00:38:56
回答 4查看 57.2K关注 0票数 22

我刚刚开始一个类来处理到TCP服务器的客户端连接。下面是我到目前为止编写的代码:

代码语言:javascript
复制
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设置为在内存中引用这个实例。是?

如果这是真的,那么我就不明白为什么要将属性用于除本机类型之外的任何东西。我可以想象,如果使用大量成员复制类实例,可能会带来相当大的性能损失。另外,对于这段代码,我可以想象复制的套接字实例不会真正工作,但我还没有对它进行测试。

无论如何,如果你能证实我的理解,或者解释我模糊逻辑中的缺陷,我会非常感激的。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2010-12-08 01:20:10

请记住,ByVal 仍然传递引用。的不同之处在于您得到了引用的副本。

因此,在重载的构造函数上,我接受对System.Net.Sockets.Socket实例的引用,是吗?

是的,但是如果你要求它的话,ByVal也是如此。不同的是,通过ByVal,您可以得到引用的副本--您有了新的变量。对于ByRef,它是相同的变量。

据我理解,内存中的实例是复制的。

不是的。只复制引用。因此,您仍然在处理同一个实例。

下面是一个代码示例,可以更清楚地解释它:

代码语言:javascript
复制
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
票数 15
EN

Stack Overflow用户

发布于 2010-12-08 00:45:58

我认为您混淆了引用与值类型以及ByValByRef的概念。即使他们的名字有点误导,他们是正交的问题。

ByVal在VB.NET中意味着将向函数发送所提供的值的副本。用于值类型(IntegerSingle等)这将提供该值的浅表副本。对于较大的类型,这可能是低效的。但是,对于引用类型(String,类实例),将传递引用的副本。由于副本是通过=以突变形式传递给参数的,所以调用函数不会看到它。

ByRef在VB.NET中意味着对原始值的引用将发送给函数(1)。这几乎就像在函数中直接使用原始值一样。像=这样的操作将影响原始值,并在调用函数中立即可见。

Socket是一个引用类型(read ),因此与ByVal一起传递它很便宜。尽管它确实执行了一个副本,但它是引用的副本,而不是实例的副本。

(1)这并不是100%正确的,因为VB.NET实际上支持调用站点上的几种ByRef。有关详细信息,请参阅博客条目https://devblogs.microsoft.com/vbteam/the-many-cases-of-byref/

票数 55
EN

Stack Overflow用户

发布于 2010-12-08 01:31:46

我的理解一直是,ByVal/ByRef决定对于值类型(在堆栈上)来说是最重要的。ByVal/ByRef对于引用类型(在堆上)几乎没有什么区别,除非该引用类型是类似于不可变的的System.String。对于可变对象,传递对象ByRef或ByVal并不重要,如果在方法中修改对象,调用函数将看到修改。

套接字是可变的,所以您可以传递任何您想要的方式,但是如果您不想对对象进行修改,您需要自己进行深入的复制。

代码语言:javascript
复制
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
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4383167

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档