复制对象并使用复制而不更改原始

时间:2012-02-10 18:45:05

标签: c#

假设我有一个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; }
}

8 个答案:

答案 0 :(得分:18)

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

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

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

答案 1 :(得分:12)

您实际上无法复制对象,因为它们更可能是引用类型。 理想的方法是将对象序列化或流式化为新的 - 假设您的类是可序列化的(通过在类声明中提供[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]属性声明。

答案 2 :(得分:10)

要更改一个实例而不更改另一个实例,您需要克隆此实例的实际值而不是引用。 .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
        }; 
    }
 }

现在注意到在使用Clone()时你需要一个显式的强制转换(或者你可以自己创建返回ItemVO)。

duplicateItemVO = (ItemVO) originalItemVO.Clone(); 

答案 3 :(得分:5)

要按值(而不是引用)复制对象,可以对其进行序列化(例如JSON),然后在其后反序列化。然后,您将获得一个按值复制。

这是一个例子

driver.Url = "https://www.booking.com/";
new WebDriverWait(driver, TimeSpan.FromSeconds(10)).Until(ExpectedConditions.ElementToBeClickable(By.CssSelector("label.xp__input#xp__guests__toggle"))).Click();
new WebDriverWait(driver, TimeSpan.FromSeconds(10)).Until(ExpectedConditions.ElementToBeClickable(By.CssSelector("button[aria-label='Increase number of Adults']"))).Click();
new WebDriverWait(driver, TimeSpan.FromSeconds(10)).Until(ExpectedConditions.ElementToBeClickable(By.CssSelector("button[aria-label='Increase number of Children']"))).Click();
new WebDriverWait(driver, TimeSpan.FromSeconds(10)).Until(ExpectedConditions.ElementToBeClickable(By.CssSelector("button[aria-label='Increase number of Children']"))).Click();
new WebDriverWait(driver, TimeSpan.FromSeconds(10)).Until(ExpectedConditions.ElementToBeClickable(By.CssSelector("button[aria-label='Increase number of Rooms']"))).Click();

答案 4 :(得分:4)

类是reference type,当你更改一个实例时,它将改变原始参考。所以使用value type对象来克服你的任务(例如:使用struct代替类)

public struct ItemVO { *** }

或者您可以为您的班级实施ICloneable Interface

答案 5 :(得分:3)

我建议按原样使用以下链接。 对我而言,它运作良好。

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

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

答案 6 :(得分:0)

默认对象是引用类型。

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

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

答案 7 :(得分:0)

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

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

如果您希望实现深层复制(类中的所有内容都被复制为新实例),那么序列化或反射可能是最好的工具