Подтвердить что ты не робот

Как сделать копию объекта в С#

Скажем, что у меня есть класс:

class obj
{
  int a;
  int b;
}

а затем у меня есть этот код:

obj myobj = new obj(){ a=1, b=2}
obj myobj2 = myobj;

Теперь приведенный выше код делает ссылку на первый объект. Я хочу, чтобы myobj2 ссылался на копию myobj с изменениями, которые не отражаются в оригинале. Я искал SO, и решения до сих пор кажутся сложными. Есть ли более простой способ сделать это. Я использую .net 4.5

4b9b3361

Ответ 1

Свойства в вашем объекте являются типами значений, и вы можете использовать мелкую копию в такой ситуации:

obj myobj2 = (obj)myobj.MemberwiseClone();

Но в других ситуациях, например, если какие-либо элементы являются ссылочными типами, вам нужен Deep Copy. Вы можете получить глубокую копию объекта с использованием методов Serialization и Deserialization с помощью класса BinaryFormatter:

public static T DeepCopy<T>(T other)
{
    using (MemoryStream ms = new MemoryStream())
    {
        BinaryFormatter formatter = new BinaryFormatter();
        formatter.Context = new StreamingContext(StreamingContextStates.Clone);
        formatter.Serialize(ms, other);
        ms.Position = 0;
        return (T)formatter.Deserialize(ms);
    }
}

Цель установки StreamingContext: мы можем внедрить специальную логику сериализации и десериализации в наш код с помощью реализации ISerializable или использования встроенных атрибутов, таких как OnDeserialized, OnDeserializing, OnSerializing, OnSerialized. Во всех случаях StreamingContext будет передан в качестве аргумента методам (и специальному конструктору в случае интерфейса ISerializable). Установив ContextState в Clone, мы просто даем подсказку этому методу о цели сериализации.

Дополнительная информация: (Вы также можете прочитать эту статью из MSDN)

При поверхностном копировании создается новый объект, а затем копируются нестатические поля текущего объекта в новый объект. Если поле является типом значения, выполняется побитовая копия поля; для ссылочного типа ссылка копируется, а ссылочный объект - нет; поэтому исходный объект и его клон ссылаются на один и тот же объект.

Глубокая копия создает новый объект, а затем копирует нестатические поля текущего объекта в новый объект. Если поле является типом значения, выполняется побитовая копия поля. Если поле является ссылочным типом, выполняется новая копия упомянутого объекта.

Ответ 2

Вы можете использовать MemberwiseClone

obj myobj2 = (obj)myobj.MemberwiseClone();

Копия - это мелкая копия, которая означает, что ссылочные свойства в клоне указывают на те же значения, что и исходный объект, но это не должно быть проблемой в вашем случае, поскольку свойства в obj имеют типы значений.

Если у вас есть исходный код, вы также можете реализовать ICloneable

Ответ 3

Похоже на то, что вы ищете простой способ свободно связывать свои объекты, но сохраняйте возможность разрешать изменения значений при необходимости.

Один из способов передачи значений между классами может быть таким.

public class Folders
{
     public string Source { get; private set; }
     public string Target { get; private set; }

     public Folders(string source, string target) 
     {
         if (String.IsEmptyOrNull(source) && String.IsEmptyOrNull(target))
         {
              throw new Exception("Null Parameter");
         }
         else
         {
               Source = source;
               Target = target;
          }
     }
}

Итак, мы создали конкретный объект с именем Folders. Теперь это можно вызвать в файле второго класса, например:

public bool CopyDirectory(string _source, string _destination)
{
    var dirStack = new Stack<Folders>();
    dirStack.Push(new Folders(_source, _destination));

    // Perform stuff related to this method.
}

Итак, в нашем втором классе мы передаем параметры наших методов этому оригинальному классу, который установит наши значения и позволит нам манипулировать ими.

У нас есть другой способ, поэтому в отдельном классе мы предположим, что хотим использовать наш конструктор для передачи переменных. Это позволит использовать начальную ссылку, а затем возможность фактического отклонения, если мы выберем.

public class DirectoryManagement
{
    private Folders _folder { get; private set; }
    public DirectoryManagement(Folders folder)
    {
        _folder = folder;
    }

}

Поэтому, когда мы используем этот способ, мы фактически гарантируем, что параметры, первоначально переданные нашему классу Folders, передаются в наш новый класс DirectoryManagement. Это позволило бы нам связать эти значения с другими переменными, использовать эти значения или любые наши потребности.

Я не уверен, что этот подход или подход, приведенный в списке, являются вашим идеальным решением. Но я подумал, что я бы представил другой способ передачи и использования существующих переменных. Также можно найти некоторые сведения о MemberwiseClone.