是否可以在 .NET 中的调用中强制将对象作为“ByVal”(作为副本)传递?

Can I force an object to be passed as "ByVal" (as a copy) in a call in .NET?

提问人:Gowire 提问时间:5/18/2017 更新时间:5/18/2017 访问量:263

问:

在下面的 VB.NET 代码中,我想将三个人添加到人员列表中。我以为我可以一遍又一遍地使用同一个人名对象,并在下次添加调用之前简单地更改它的名称。我希望每个调用都应该复制对象并将该副本添加到列表中......但我最终得到了三个“Kim”的清单。列表元素似乎引用同一个对象。

Class Person
    Public Name As String
End Class

Sub Foo()
    Dim Persons as New List(Of Person)
    Dim aPerson As New Person

    aPerson.Name = "John"
    Persons.Add(aPerson)
    aPerson.Name = "Emma"
    Persons.Add(aPerson)
    aPerson.Name = "Kim"
    Persons.Add(aPerson)
End Sub

我可以强制在每个 Add-call 中复制它吗?或者我需要为 John、Emma 和 Kim 创建单独的对象吗?aPerson

vb.net 对象 按值传递

评论

1赞 Alex B. 5/18/2017
Or do I need to create separate objects for John, Emma and Kim?是的,你必须
1赞 Zedee.Chen 5/18/2017
你应该给出不同的对象。
0赞 jmcilhinney 5/18/2017
所有引用类型(即类)都以这种方式运行。如果是一个结构,那么你显示的代码就会起作用,因为添加到列表中会创建一个副本。这可能使使用结构而不是类看起来是一个好主意,但事实并非如此。类以这种方式工作的原因有很多,在类合适的地方使用结构可能会导致许多问题。结构有其用途,但这通常仅适用于小型、不可变类型。类在绝大多数时间里都应该使用。这可能看起来很奇怪,但你会习惯的。Person
0赞 Gowire 5/18/2017
但是,为什么当 aPerson 在 End Sub 之后被摧毁时,对对象的引用没有被破坏。 毕竟,在某个地方似乎存在该对象的副本......原始对象被销毁后存在的副本...?

答:

1赞 Mederic 5/18/2017 #1

你正在做的事情不是好的做法,因为你不应该以这种方式使用类。

如果你的名字来自列表等来源,你可以使用循环。For Each

Dim MyNames As New List(Of String)
MyNames.Add("John")
MyNames.Add("Emma")
MyNames.Add("Kim")
For Each person_name As String In MyNames
    Dim aPerson As New Person
    aPerson.Name = person_name 
    Persons.Add(aPerson)
Next

例如,如果数据来自文件、SQL 请求或 JSON,则这种方法可能非常实用。

否则,您只会有:

Dim Persons as New List(Of Person)
Dim aPerson As New Person
Dim bPerson As New Person
Dim cPerson As New Person
aPerson.Name = "John"
Persons.Add(aPerson)
bPerson.Name = "Emma"
Persons.Add(bPerson)
cPerson.Name = "Kim"
Persons.Add(cPerson)

评论

0赞 A Friend 5/18/2017
For应该是 。将提交编辑,但它低于字符限制,其余的答案很棒。For Each
0赞 Mederic 5/18/2017
@AFriend哈哈谢谢,我完全忘了添加它,发帖时没有注意到