创建一个此对象的“克隆”,而不是指向它。

17

假设我有一个名为

myFirstList

然后我想创建一个该列表的副本,以便我可以进行一些自己的调整。所以我这样做:

mySecondList = myFirstList
mySecondList.doTweaks

但是我注意到这些修改也会影响myFirstList对象!我只想修改第二个列表...

之后我还想完全删除mySecondList,所以我执行mySecondList = Nothing,那我就好了,对吗?

8个回答

20

Adam Rackis,我不喜欢你的“当然会”的回答,因为这一点都不显然。

如果你有一个字符串变量,将其赋给另一个字符串变量时,当更改其中一个变量时并不会同时更改它们两个。它们并不指向同一块物理内存,那么为什么很明显类会这样做呢?

而且,情况甚至连贯性都没有。在以下情况下,数组中的所有元素将指向同一个对象(它们最终都将具有设置为10的“Number”变量):

SourceObject = New SomeClass
For i = 1 To 10
   SourceObject.Number = i
   ObjectArray.Add = SourceObject   
Next i

但是,以下内容将为您提供10个不同的实例:

For i = 1 To 10
   SourceObject = New SomeClass
   SourceObject.Number = i
   ObjectArray.Add = SourceObject   
Next i

显然,对象的范围很重要,因此发生了什么事情并不明显。


5
对我来说,这似乎也一直是违反直觉的。令人惊奇的是,即使过去10年了,仍然没有任何简单的.NET函数或方法可以进行深度克隆。当.NET问世时,内存确实很珍贵,但现在呢? - Mike Honey

9
以下是操作步骤:

如何进行操作:

'copy one object to another via reflection properties
For Each p As System.Reflection.PropertyInfo In originalobject.GetType().GetProperties()
    If p.CanRead Then
        clone.GetType().GetProperty(p.Name).SetValue(clone, p.GetValue(OriginalObject, Nothing))
    End If
Next

在某些情况下,当克隆对象具有只读属性时,您需要首先进行检查。

For Each p As System.Reflection.PropertyInfo In originalobject.GetType().GetProperties()
    If p.CanRead AndAlso clone.GetType().GetProperty(p.Name).CanWrite Then
        clone.GetType().GetProperty(p.Name).SetValue(clone, p.GetValue(OriginalObject, Nothing))
    End If
Next

谢谢!运行得非常好。 - Laki Politis
好的,我在这里缺少什么?“Clone未声明”。 - tolsen64

7

由于您没有透露存储在列表中的项目类型,我假设它实现了IClonable接口(否则,如果可以的话,请实现IClonable接口,或找到一种方式来克隆列表中的个别项目)。

尝试这样做:

mySecondList = myFirstList.[Select](Function(i) i.Clone()).ToList()

5
扩展Adam Rackies的答案,我使用VB.NET实现了以下代码。
我的目标是复制一个对象列表,这些对象主要用作数据传输对象(即数据库数据)。首先定义类dtoNamedClass并添加ShallowCopy方法。创建一个名为dtoNamedClassCloneVar的新变量,并使用LINQ select查询来复制对象变量dtoNamedClassVar。
我能够对dtoNamedClassCloneVar进行更改而不影响dtoNamedClassVar。
Public Class dtoNamedClass


    ... Custom dto Property Definitions



  Public Function ShallowCopy() As dtoNamedClass
    Return DirectCast(Me.MemberwiseClone(), dtoNamedClass)
  End Function

End Class


Dim dtoNamedClassVar As List(Of dtoNamedClass) = {get your database data}

Dim dtoNamedClassCloneVar = 
    (From d In Me.dtoNamedClass
        Where {add clause if necessary}
        Select d.ShallowCopy()).ToList

被低估的答案!这很有帮助!你能详细说明一下ShallowCopy()中复制的“多浅”/“多深”吗? - DarkTrick

4
当然会影响到它。两个变量都指向内存中的同一对象。对其中一个所做的任何事情都会发生在另一个上。
根据您的要求,您需要进行深克隆或浅克隆。 这篇文章应该能够更好地帮助您理解所需操作。

1
非常有趣的信息,好的。幸运的是我成功找到了一个解决方法,但这也很好知道 :) - Saturn
1
@Adam,链接到实际实现的链接在相关文章中已经失效。 - Chad

4

以下是另一种方法,可能会更受欢迎,因为 System.Reflection 可能较慢。

您需要向您的解决方案添加 Newtonsoft.Json NuGet 包,然后执行以下操作:

Imports Newtonsoft.Json

假设有一个类类型为 MyClass,那么克隆可以非常简单:

Dim original as New MyClass
'populate properties of original...
Dim copy as New MyClass
copy = JsonConvert.DeserializeObject(Of MyClass)(JsonConvert.SerializeObject(original))

所以,首先使用JSON转换器将original对象序列化,然后取该序列化数据进行反序列化 - 指定类类型 - 成为类实例copy。JSON转换器非常强大和灵活;如果需要进行基本方法无法解决的自定义属性映射和操作,您可以执行各种操作。

因为这确实对我有用,所以点赞! - kosherjellyfish

2
这对我有效:

这对我有效:

mySecondList = myFirstList.ToList

-1

clone 是你试图克隆的对象。

dim clone as new YourObjectType

你可以像这样声明它。


你好,欢迎来到SO。我不太理解你的回答。你是在回复tolson64对deuan的回答的评论吗? - Fabio says Reinstate Monica

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接