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

Скопировать класс, С#

Есть ли способ скопировать класс в С#? Что-то вроде var dupe = MyClass (оригинал).

4b9b3361

Ответ 1

Вероятно, вы говорите о глубокой копии (глубокой копии или мелкой копии)?

Вам либо нужно:

  • реализовать (жесткий код) собственный метод,
  • попытайтесь реализовать (или найти) реализацию, использующую Reflection или Emit, чтобы сделать это динамически (объяснил здесь),
  • используйте сериализацию и десериализацию для создания глубокой копии, если объект помечен атрибутом [Serializable].
public static T DeepCopy<T>(T other)
{
    using (MemoryStream ms = new MemoryStream())
    {
        BinaryFormatter formatter = new BinaryFormatter();
        formatter.Serialize(ms, other);
        ms.Position = 0;
        return (T)formatter.Deserialize(ms);
    }
}

Чтобы получить мелкую копию, вы можете использовать метод Object.MemberwiseClone(), но это защищенный метод, что означает, что вы можете использовать его только внутри класса.

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

Ответ 2

Не все классы имеют эту функциональность. Вероятно, если класс делает, он предоставляет метод Clone. Чтобы помочь реализовать этот метод для ваших собственных классов, существует защищенный метод MemberwiseClone, определенный в System.Object, который делает мелкую копию текущего экземпляра (т.е. поля копируются, если они являются ссылочными типами, ссылка указывает на исходное местоположение).

Ответ 3

Если ваш класс только что получил свойства, вы можете сделать что-то вроде этого:

SubCentreMessage actual;
actual = target.FindSubCentreFullDetails(120); //for Albany
SubCentreMessage s = new SubCentreMessage();

//initialising s with the same values as 
foreach (var property in actual.GetType().GetProperties())
{
    PropertyInfo propertyS = s.GetType().GetProperty(property.Name);
    var value = property.GetValue(actual, null);
    propertyS.SetValue(s, property.GetValue(actual, null), null);
}

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

Ответ 4

Я думаю, автор спрашивает о конструкторах копирования...

Ответ: "да, но только если вы его реализуете самостоятельно", нет "автоматического" способа сделать это без каких-либо тяжелых неудобств (читает: Reflection):

class MyClass {
    private string _name;

    // standard constructor, so that we can make MyClass without troubles
    public MyClass(string name) {_name = name}
    public MyClass(MyClass old) {
        _name = old._name;
        // etc...
    }
}

В этом отношении следует отметить интерфейс IClonable и метод .Clone(), который предоставляет. Также защищенный метод .MemberwiseClone(), предоставляемый классом Object, может помочь реализовать оба этих метода.

Ответ 5

Да и нет. Это область, где вам нужно быть немного осторожным, потому что есть некоторые ловушки (а потом снова это не сложно).

Прежде всего, если вы немного сориентируете библиотеку базового класса (BCL), вы можете обнаружить ICloneable interface. Не все типы реализуют этот интерфейс, но те, у которых есть метод Clone, который вернет новый экземпляр того же типа с (предположительно) теми же значениями.

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

Если вы копаете дальше в BCL, вы можете обнаружить, что System.Object имеет защищенный метод MemberwiseClone. Хотя вы не можете вызвать этот метод непосредственно из другого типа, вы можете использовать этот метод для реализации клонирования в ваших собственных объектах.

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

public class MyClass()
{
    public MyClass() {}

    protected MyClass(MyClass other)
    {
        // Cloning code goes here...
    }

    public MyClass Clone()
    {
        return new MyClass(this);
    }
}

Однако это явно работает только если вы управляете типом, который хотите клонировать.

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

Ответ 6

Как с JSON?

Вы можете получить пакет JSON от: https://www.nuget.org/packages/Newtonsoft.Json/

using Newtonsoft.Json;
public static List<T> CopyAll<T>(this List<T> list) {
  List<T> ret = new List<T>();
  string tmpStr = JsonConvert.SerializeObject(list);
  ret = JsonConvert.DeserializeObject<List<T>>(tmpStr);
  return ret;
}

Ответ 7

Непростой способ, который всегда будет работать. Если ваш класс [Serializable] или реализует ISerializable, вы можете сделать сериализацию в оба конца, чтобы создать идентичную копию. То же самое работает для [DataContract]

Если вам нужна только небольшая копия, вы можете попробовать Object.MemberwiseClone(). Это защищенный метод, хотя вы можете использовать его только внутри класса.

Если вам повезет, класс реализует ICloneable, и вы можете просто вызвать метод Clone().

Ответ 8

Одна из возможностей заключается в clone it. Вы должны реализовать интерфейс ICloneable и Clone.

Ответ 9

Вы имеете в виду конструктор копирования, как он существует в С++?

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

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

Ответ 10

Легкий способ клонирования объекта записывает его в поток и читает его снова:

public object Clone()
{
    object clonedObject = null;
    BinaryFormatter formatter = new BinaryFormatter();
    using (Stream stream = new MemoryStream())
    {
        formatter.Serialize(stream, this);
        stream.Seek(0, SeekOrigin.Begin);
        clonedObject = formatter.Deserialize(stream);
    }

    return clonedObject;
}

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

Ответ 11

Как насчет чего-то типа:

public class MyClass 
{
    int i;
    double d;
    string something;

    public MyClass(int i, double d) {}

    public MyClass Clone()
    {
        return (new MyClass(i, d));
    }
}

Или, если вам также нужно скопировать что-то другое, которое обычно не известно при создании нового объекта:

    public MyClass CloneMore()
    {
        MyClass obj = new MyClass(i, d);
        obj.something = this.something;
        return (obj);
    }

Вызов с использованием:

MyClass us = them.Clone();

~~~

Ответ 12

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

using System.Reflection; using System.Text.StringBuilder();

public static T CopyClass2<T>(T obj){
    T objcpy = (T)Activator.CreateInstance(typeof(T));
    obj.GetType().GetProperties().ToList()
    .ForEach( p => objcpy.GetType().GetProperty(p.Name).SetValue(objcpy, p.GetValue(obj)));
    return objcpy;

}

И вот более вербальная версия, я полагаю, выше предлагает вам понять Лямбда-выражения, которые не распространены. Если вы уважаете читабельность (которая полностью действительна) больше я буду использовать ниже

public static T CopyClass<T>(T obj)
{
    T objcpy = (T)Activator.CreateInstance(typeof(T));
    foreach (var prop in obj.GetType().GetProperties())
    {
        var value = prop.GetValue(obj);
        objcpy.GetType().GetProperty(prop.Name).SetValue(objcpy, value);
    }
    return objcpy;

}

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

public static string ListAllProperties<T>(T obj)
{
        StringBuilder sb = new System.Text.StringBuilder();
        PropertyInfo[] propInfo = obj.GetType().GetProperties();
        foreach (var prop in propInfo)
        {
            var value = prop.GetValue(obj) ?? "(null)";
            sb.AppendLine(prop.Name + ": " + value.ToString());
        }
        return sb.ToString();
}