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

Как клонировать объекты

Когда я делаю следующее: все, что делается с Person b, изменяет Person a (я думал, что это будет клонировать Person b от Person a). У меня также нет идеи, если смена Person a изменит Person b после ссылки. Из-за моего кода прямо сейчас, я могу видеть это только в одном направлении.

Person a = new Person() { head = "big", feet = "small" };
Person b = a; 

b.head = "small"; //now a.head = "small" too   

Теперь, если я сделаю это вместо этого. Человек a станет полностью отдельным.

Person b = new Person() { head = a.head, feet = a.feet };

Теперь это прекрасно и любопытно имеет смысл при сравнении этого поведения с другими вещами на С#. НО, это может сильно раздражать большие объекты.

Есть ли способ сократить это вообще?

Например:

Person b = a.Values;

4b9b3361

Ответ 1

Есть ли способ сократить это вообще?

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

  • Если ваш тип struct, а не class, он будет скопирован по значению (вместо простого копирования ссылки на экземпляр). Это даст вам семантику, которую вы описываете, но имеет много других побочных эффектов, которые, как правило, менее желательны и не рекомендуются для какого-либо изменяемого типа (что, очевидно, это или это не будет проблемой!)

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

  • Использовать отражение, MemberwiseClone или аналогично копировать все значения, поэтому вам не нужно писать код для этого. У этого есть потенциальные проблемы, особенно если у вас есть поля, содержащие непростые типы.

Ответ 2

То, что вы ищете, - это клонирование. Вам нужно будет выполнить IClonable, а затем выполнить клонирование.

Пример:

class Person() : ICloneable
{
    public string head;
    public string feet; 

    #region ICloneable Members

    public object Clone()
    {
        return this.MemberwiseClone();
    }

    #endregion
}

Затем вы можете просто вызвать метод Clone для создания ShallowCopy (в этом конкретном случае также DeepCopy)

Person a = new Person() { head = "big", feet = "small" };
Person b = (Person) a.Clone();  

Вы можете использовать метод MemberwiseClone класса Object для клонирования.

Ответ 3

Я использую AutoMapper для этого. Это работает так:

Mapper.CreateMap(typeof(Person), typeof(Person));
Mapper.Map(a, b);

Теперь человек а обладает всеми свойствами человека б.

Кроме того, AutoMapper работает и для разных объектов. Для получения дополнительной информации, проверьте это на http://automapper.org

Обновление: сейчас я использую этот синтаксис (упрощенно - на самом деле CreateMaps находятся в профилях AutoMapper):

Mapper.CreateMap<Person, Person>;
Mapper.Map(a, b);

Обратите внимание, что вам не нужно создавать CreateMap для сопоставления одного объекта того же типа с другим, но если вы этого не сделаете, AutoMapper создаст мелкую копию, что означает для непрофессионала, что если вы измените один объект, другой меняется также.

Ответ 4

Так как метод MemberwiseClone() не является общедоступным, я создал этот простой метод расширения, чтобы упростить клонирование объектов:

public static T Clone<T>(this T obj)
{
    var inst = obj.GetType().GetMethod("MemberwiseClone", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);

    return (T)inst?.Invoke(obj, null);
}

Использование:

var clone = myObject.Clone();

Ответ 5

Чтобы клонировать объект класса, вы можете использовать метод Object.MemberwiseClone,

просто добавьте эту функцию в свой класс:

public class yourClass
{
    // ...
    // ...

    public yourClass DeepCopy()
    {
        yourClass othercopy = (yourClass)this.MemberwiseClone();
        return othercopy;
    }
}

чтобы выполнить глубокую независимую копию, просто вызовите метод DeepCopy:

yourClass newLine = oldLine.DeepCopy();

Ответ 6

a и b - это просто две ссылки на один и тот же объект Person. Они оба по существу держат адрес Person.

Существует интерфейс ICloneable, хотя относительно немногие классы поддерживают его. С этим вы бы написали:

Person b = a.Clone();

Тогда б был бы совершенно отдельным Person.

Вы также можете реализовать конструктор копирования:

public Person(Person src)
{
  // ... 
}

Нет встроенного способа скопировать все поля. Вы можете сделать это с помощью рефлексии, но это приведет к снижению производительности.

Ответ 7

Безболезненно: использование библиотеки NClone

Person a = new Person() { head = "big", feet = "small" };
Person b = Clone.ObjectGraph(a); 

Ответ 8

  public static T Clone<T>(T obj)
  {
      DataContractSerializer dcSer = new  DataContractSerializer(obj.GetType());
      MemoryStream memoryStream = new MemoryStream();

      dcSer.WriteObject(memoryStream, obj);
      memoryStream.Position = 0;

      T newObject = (T)dcSer.ReadObject(memoryStream);
      return newObject;
  }

Ответ 9

Вы можете сделать это следующим образом:

var jss = new JavaScriptSerializer();
var b = jss.Deserialize<Person>(jss.Serialize(a));

Для глубокого клонирования вы можете взглянуть на этот ответ: fooobar.com/questions/594/...

Ответ 10

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

public static class CloneUtil<T>
{
    private static readonly Func<T, object> clone;

    static CloneUtil()
    {
        var cloneMethod = typeof(T).GetMethod("MemberwiseClone", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
        clone = (Func<T, object>)cloneMethod.CreateDelegate(typeof(Func<T, object>));
    }

    public static T ShallowClone(T obj) => (T)clone(obj);
}

public static class CloneUtil
{
    public static T ShallowClone<T>(this T obj) => CloneUtil<T>.ShallowClone(obj);
}

Вы можете назвать это так:

Person b = a.ShallowClone();

Ответ 11

Это происходит потому, что "Person" - это класс, поэтому он передается по ссылке. В заявлении "b = a" вы просто копируете ссылку на экземпляр "Person", который вы создали с ключевым словом new.

Самый простой способ иметь поведение, которое вы ищете, - использовать "тип значения".

Просто измените объявление Person из

class Person

к

struct Person