.Net Глубокое клонирование - каков наилучший способ сделать это?

Мне нужно выполнить глубокое клонирование моей сложной объектной модели. Как вы думаете, что является лучшим способом сделать это в.Net?
Я думал о сериализации / десериализации
не нужно упоминать, что MemberwiseClone не достаточно хорош

7 ответов

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

Это один из случаев, когда BinaryFormatter работает приемлемо; обычно я не фанат (из-за проблем с версионированием и т. д.) - но поскольку сериализованные данные предназначены для немедленного использования, это не проблема.

Если вы хотите это немного быстрее (но без вашего собственного кода), то protobuf-net может помочь, но требует изменения кода (для добавления необходимых метаданных и т. д.). И это на основе дерева (не на основе графа).

Другие сериализаторы (XmlSerializer, DataContractSerializer) также хорошо, но если это только для клона, они могут не предлагать слишком много BinaryFormatter (разве что XmlSerializer не нужно [Serializable],

Так что на самом деле, это зависит от ваших конкретных классов и сценария.

Если вы выполняете код в среде с частичным доверием, такой как Rackspace Cloud, вам, скорее всего, будет запрещено использовать BinaryFormatter. Вместо этого можно использовать XmlSerializer.

public static T DeepClone<T>(T obj)
{
    using (var ms = new MemoryStream())
    {
        XmlSerializer xs = new XmlSerializer(typeof(T));
        xs.Serialize(ms, obj);
        ms.Position = 0;

        return (T)xs.Deserialize(ms);
    }
}

Пример глубокого клонирования из журнала msdn:

    Object DeepClone(Object original)
    {
        // Construct a temporary memory stream
        MemoryStream stream = new MemoryStream();

        // Construct a serialization formatter that does all the hard work
        BinaryFormatter formatter = new BinaryFormatter();

        // This line is explained in the "Streaming Contexts" section
        formatter.Context = new StreamingContext(StreamingContextStates.Clone);

        // Serialize the object graph into the memory stream
        formatter.Serialize(stream, original);

        // Seek back to the start of the memory stream before deserializing
        stream.Position = 0;

        // Deserialize the graph into a new set of objects
        // and return the root of the graph (deep copy) to the caller
        return (formatter.Deserialize(stream));
    }

Пожалуйста, взгляните на действительно хорошую статью C# Object Clone Wars. Я нашел очень интересное решение там: Копируемый: платформа для копирования или клонирования объектов.NET

Лучший способ реализовать это вручную. Это будет действительно быстрее, чем любые другие общие методы. Также есть много библиотек для этой операции (здесь вы можете увидеть список с тестами производительности).

Кстати, BinaryFormatter очень медленный для этой задачи и может быть полезен только для тестирования.

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

Наилучшим способом, вероятно, является реализация интерфейса System.IClonable в вашем объекте и во всех его полях, которые также требуют специальных возможностей глубокого клонирования. Затем вы реализуете метод Clone для возврата глубокой копии вашего объекта и его членов.

Другие вопросы по тегам