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

Got*_*cha 27 c#

假设我有一个Object ItemVO,其中已经分配了一堆属性.例如:

ItemVO originalItemVO = new ItemVO();
originalItemVO.ItemId = 1;
originalItemVO.ItemCategory = "ORIGINAL";
Run Code Online (Sandbox Code Playgroud)

我想通过使用以下方法创建另一个副本:

duplicateItemVO = originalItemVO;
Run Code Online (Sandbox Code Playgroud)

然后使用duplicateItemVO并更改其'属性,而不更改originalItemVO:

// This also change the originalItemVO.ItemCategory which I do not want.
duplicateItemVO.ItemCategory = "DUPLICATE" 
Run Code Online (Sandbox Code Playgroud)

如何在不更改ItemVO类的情况下实现此目的?

谢谢

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

    public string ItemId { get; set; }
    public string ItemCategory { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

Ree*_*sey 19

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

duplicateItemVO = new ItemVO 
    { 
        ItemId = originalItemVO.ItemId, 
        ItemCategory = originalItemVO.ItemCategory 
    };
Run Code Online (Sandbox Code Playgroud)

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

  • @Gotcha在类中创建一个可以处理第二个实例的构造函数,并在内部适当地进行设置.这是最易维护的方法 - 然后你只需写:`duplicateItemVO = new ItemVO(originalItemVO);` (3认同)

小智 16

要按值而不是引用复制对象,您可以序列化它(例如 JSON),然后立即反序列化它。然后你有一个按值的副本。

这是一个例子

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

string json = Newtonsoft.Json.JsonConvert.SerializeObject(originalItemVO); 
ItemVO duplicateItemVO = Newtonsoft.Json.JsonConvert.DeserializeObject<ItemVO>(json);
Run Code Online (Sandbox Code Playgroud)

  • 欢迎来到SO!请考虑在您的答案中添加一些解释或评论。一般来说,不鼓励只用原始代码而不用其他任何东西来发布答案。此外,如果您回答一个有大量答案的过时问题,请考虑是否为该主题带来了任何新内容(有一个非常相似的答案使用反序列化)。 (2认同)

Sof*_*ide 12

为了更改一个实例而不更改另一个实例,您需要克隆此实例的实际值而不是引用..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
        }; 
    }
 }
Run Code Online (Sandbox Code Playgroud)

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

duplicateItemVO = (ItemVO) originalItemVO.Clone(); 
Run Code Online (Sandbox Code Playgroud)


Ven*_*l M 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);
        }
    }
Run Code Online (Sandbox Code Playgroud)

现在您可以使用此代码:

[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);
Run Code Online (Sandbox Code Playgroud)

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


小智 6

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

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

 public Person ShallowCopy ()
 {
    return (Person) this.MemberwiseClone ();
 }
Run Code Online (Sandbox Code Playgroud)


Cha*_*mal 5

class 是引用类型,当您更改一个实例时,它将更改原始引用。所以使用值类型对象来克服你的任务(例如:使用结构而不是类)

public struct ItemVO { *** }
Run Code Online (Sandbox Code Playgroud)

或者你可以为你的类实现 ICloneable 接口