Duplicate Object и работа с Duplicate без изменения оригинала - PullRequest
25 голосов
/ 10 февраля 2012

Предполагается, что у меня есть Object ItemVO, в котором уже есть набор свойств. например:

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

Я хотел бы создать еще один дубликат, используя:

duplicateItemVO = originalItemVO;

и затем используйте duplicateItemVO и измените его свойства, БЕЗ изменения оригинальногоItemVO:

// 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; }
}

Ответы [ 7 ]

18 голосов
/ 10 февраля 2012

Вам нужно будет создать новый экземпляр вашего класса, а не просто присвоить переменную:

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

Когда вы имеете дело со ссылочными типами (любым классом), просто присвоение переменной создаеткопия ссылки на оригинальный объект.Таким образом, установка значений свойств в этом объекте также изменит оригинал.Чтобы предотвратить это, вам необходимо создать новый экземпляр объекта.

12 голосов
/ 26 августа 2014

Практически невозможно скопировать объект, поскольку он, скорее всего, относится к ссылочным типам.Идеальным методом является сериализация или потоковая передача объекта в новый - при условии, что ваш класс сериализуем (предоставив атрибут [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].

10 голосов
/ 10 февраля 2012

Чтобы изменить один экземпляр без изменения другого, необходимо клонировать действительные значения этого экземпляра, а не ссылку. Шаблон, используемый в .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(); 
4 голосов
/ 10 февраля 2012

класс ссылочный тип , и при изменении одного экземпляра это изменит исходную ссылку.поэтому используйте тип значения объект для преодоления вашей задачи (например: используйте struct вместо класса)

public struct ItemVO { *** }

или вы можете реализовать ICloneable Interface для вашего класса

3 голосов
/ 04 сентября 2017

Я предлагаю использовать как есть в ссылке ниже. Для меня это сработало очень хорошо.

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

 public Person ShallowCopy ()
 {
    return (Person) this.MemberwiseClone ();
 }
0 голосов
/ 19 июля 2015

Начиная с c # 4.5, объект базового класса содержит метод MemberwiseClone, который позволяет выполнить поверхностную копию этого объекта и возвращает результат в качестве нового экземпляра. (Если поле является типом значения, выполняется побитовая копия поля. Если поле является ссылочным типом, ссылка копируется, а ссылочный объект - нет; поэтому исходный объект и его клон ссылаются к тому же объекту.)

Это полезно, если вы хотите реализовать шаблон проектирования прототипа.

Если вы хотите реализовать глубокое копирование (все внутри класса дублируется как новые экземпляры), то сериализация или рефлексия, вероятно, являются лучшими инструментами

0 голосов
/ 22 октября 2013

По умолчанию объекты имеют ссылочный тип.

Назначение одного объекта другому объекту означает, что вы просто ссылаетесь на адрес объекта. Любые изменения в любом объекте будут отражаться в обоих.

Чтобы решить эту проблему, вам нужно инициализировать объект с помощью ключевого слова «new», а затем добавить значение этого объекта в первый объект.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...