2012-02-10 52 views
14

假设我有一个Object ItemVO,其中有一堆属性已分配。 如:重复对象和使用重复而不更改原始

ItemVO originalItemVO = new ItemVO(); 
originalItemVO.ItemId = 1; 
originalItemVO.ItemCategory = "ORIGINAL"; 

我想通过创建另一个重复:

duplicateItemVO = originalItemVO; 

,然后使用duplicateItemVO并改变其性质,不改变originalItemVO:

// This also change the originalItemVO.ItemCategory which I do not want. 
duplicateItemVO.ItemCategory = "DUPLICATE" 

我怎样才能做到这一点,而不需要改变ItemVO类?

感谢

public class ItemVO  
{ 
    public ItemVO() 
    { 
     ItemId = ""; 
     ItemCategory = ""; 
    } 

    public string ItemId { get; set; } 
    public string ItemCategory { get; set; } 
} 
+3

可能重复:http://stackoverflow.com/questions/78536/cloning-objects-in-c-sharp – Kekoa 2012-02-10 18:47:36

回答

10

您需要构建类的新实例,而不仅仅是分配变量:

duplicateItemVO = new ItemVO 
    { 
     ItemId = originalItemVO.ItemId, 
     ItemCategory = originalItemVO.ItemCategory 
    }; 

当你处理引用类型(任何类),只是分配一个变量正在创建对原始对象的引用副本。因此,在该对象中设置属性值也会更改原始值。为了防止这种情况,你需要实际构造一个新的对象实例。

+0

有另一种方式,而不是originalItemVO到duplicateItemVO明确指定每个属性?为了简单起见,我使用了一个itemVO,但是我有大约30+ – Gotcha 2012-02-10 20:34:53

+2

@Gotcha在您的类中创建一个构造函数,该函数关闭第二个实例,并在内部适当地进行设置。这是最容易维护的方法 - 那么你只需写:'duplicateItemVO = new ItemVO(originalItemVO);' – 2012-02-10 20:36:03

1

类是reference type并且当您更改一个实例时,它将更改原始参照。所以使用value type对象为克服你的任务(例如:使用struct,而不是类)

public struct ItemVO { *** } 

,或者你可以为你的类

+0

正确的,我已经想通了这么多...我宁可不改变这个类到一个结构,以避免其他影响这种变化。我只处理一小部分具有这个现有类的代码......这是我无法修改的。我还能怎么做到这一点? – Gotcha 2012-02-10 20:37:38

+0

您可以为您的类实现[ICloneable接口](http://msdn.microsoft.com/en-us/library/system.icloneable.aspx) – 2012-02-11 04:34:57

6

实施ICloneable Interface为了改变一个实例不改变,你需要克隆其他这个实例的实际值而不是参考。 .Net中使用的模式是实现ICloneable。 所以,你的代码应该是这样的:

public class ItemVO: ICloneable 
    { 
    public ItemVO() 
    { 
     ItemId = ""; 
     ItemCategory = ""; 
    } 

    public string ItemId { get; set; } 
    public string ItemCategory { get; set; } 

    public object Clone() 
    { 
     return new ItemVO 
     { 
      ItemId = this.ItemId, 
      ItemCategory = this.ItemCategory 
     }; 
    } 
} 

现在请注意您在使用克隆(当需要显式转换)(或者你可以让你自己返回ItemVO)。

duplicateItemVO = (ItemVO) originalItemVO.Clone(); 
+0

这很有道理,但假设我不能更改类ItemVO,我做到了? – Gotcha 2012-02-10 20:38:34

+1

在这种情况下,您有两种选择之一:(1)扩展该类,然后从子类实现IColneable。 (2)每次需要分配对象时都必须手动重新创建对象,要手动创建对象,只需在Clone方法中使用相同的代码即可。我首先喜欢第一种选择,特别是如果你最终在很多地方这样做。 – 2012-02-10 21:16:43

0

默认情况下,对象是引用类型。

将一个对象分配给另一个对象,这意味着您只需引用该对象的地址。任何对象的任何更改都会反映在这两个对象中。

要解决此问题,您应该使用“new”关键字初始化对象,然后将此对象值添加到第一个对象中。

6

您几乎不能复制对象,因为它们更可能是引用类型。 理想的方法是将对象序列化为一个新对象 - 假设您的类是可序列化的(通过在类声明中提供[Serializable]属性)。

private static T Clone<T>(T source) 
    { 
     if (!typeof(T).IsSerializable) 
     { 
      throw new ArgumentException("The type must be serializable.", "source"); 
     } 

     if (Object.ReferenceEquals(source, null)) 
     { 
      return default(T); 
     } 

     System.Runtime.Serialization.IFormatter formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter(); 
     Stream stream = new MemoryStream(); 
     using (stream) 
     { 
      formatter.Serialize(stream, source); 
      stream.Seek(0, SeekOrigin.Begin); 
      return (T)formatter.Deserialize(stream); 
     } 
    } 

现在你可以使用这个代码:

[Serializable] 
public class MyClass 
{ 
    public int a {get; set;} 
    public int b {get; set;} 
}  
var obj = new MyClass{ 
a = 10, 
b = 20, 
}; 

var newobj = Clone<MyClass>(obj); 

您将获得obj的一个全新的副本。 注意:MyClass中的任何其他类也必须用属性[Serializable]声明。

+0

感谢您的这个方便的珍闻!你是否在一个大对象上检查了这个性能? – callisto 2017-02-23 14:12:32

+0

是的,@callisto,我已经试过这个大对象,只要有足够的内存可用,它就可以工作。 – 2017-02-27 09:10:57

+0

谢谢!尽量使用它,而不会损害我的代码, – 2017-08-17 10:13:59

0

从c#4.5开始,基类对象包含一个名为MemberwiseClone的方法,使您可以执行该对象的浅拷贝并将结果作为新实例返回。 (如果一个字段是一个值类型,则执行该字段的逐位拷贝;如果一个字段是引用类型,则引用被复制但引用的对象不是;因此,原始对象及其克隆参考)

如果您希望实现原型设计模式,这非常有用。

如果您正在寻找实现深拷贝(一切在类被复制为新的情况下),那么序列化或反射可能是最好的工具

0

我建议使用如在下面的链接。 对我来说,它工作得很好。

https://msdn.microsoft.com/en-us/library/system.object.memberwiseclone(v=vs.110).aspx

public Person ShallowCopy() 
{ 
    return (Person) this.MemberwiseClone(); 
} 
+0

虽然此链接可能回答问题,但最好在此处包含答案的重要部分,并提供供参考的链接。如果链接页面更改,则仅链接答案可能会失效。 - [来自评论](/ review/low-quality-posts/17233687) – 2017-09-05 04:49:15