Создать копию объекта

Мне нужно клонировать объект (класс, а не структура) в.net 4.5 (C#).
Я нашел два пути:

  1. Реализация интерфейса ICloneable
  2. Создайте собственный механизм клонирования, как этот известный ответ SO

Мне нравится первый способ - это проще, но я также обнаружил интерфейс Not Implpement ICloneable, но это очень старая статья, и в MSDN я не могу найти, что этот интерфейс устарел.

Может ли кто-нибудь сказать мне, это безопасно использовать ICloneable в.net 4.5?

2 ответа

Решение

Вы не должны использовать интерфейс IClonable.

Вот блог Брэда Абрамса, в котором обсуждается, почему не несколько лет назад. В основном, причины изложены в ответе Тима Шмельтера, но этот блог из уст лошади.

Что касается реализации клонирования с помощью сериализации, то теперь есть несколько лучший способ, потому что мы можем указать StreamingContextStates.Clone чтобы клонирование работало лучше с такими вещами, как неуправляемые ручки.

В "CLR via C# 4 Edition" Джеффри Рихтера есть каноническая реализация, которая выглядит так:

public static object DeepClone(object original)
{
    using (var stream = new MemoryStream())
    {
        var formatter = new BinaryFormatter
        {
            Context = new StreamingContext(StreamingContextStates.Clone)
        };

        formatter.Serialize(stream, original);
        stream.Position = 0;

        return formatter.Deserialize(stream);
    }
}

Или строго типизированный вариант:

public static T DeepClone<T>(T original)
{
    if (!typeof(T).IsSerializable)
    {
        throw new ArgumentException("The type must be serializable.", "original");
    }

    if (ReferenceEquals(original, null))
    {
        return default(T);
    }

    using (var stream = new MemoryStream())
    {
        var formatter = new BinaryFormatter
        {
            Context = new StreamingContext(StreamingContextStates.Clone)
        };

        formatter.Serialize(stream, original);
        stream.Position = 0;

        return (T) formatter.Deserialize(stream);
    }
}

Я считаю, что вы должны использовать это (где это возможно) вместо реализации IClonable,

IClonable это просто интерфейс, поэтому он ничего не делает, пока вы его не реализуете. Пост, который предлагает не использовать IClonable упоминает почему: не ясно, если Clone реализуется как глубокая или как мелкая копия.

Так что просто предоставьте Copy или же DeepClone метод, и все знают, что происходит.

Цитата, чтобы объяснить два термина:

Существует два основных способа реализации ICloneable, как в глубоком, так и в не глубоком копировании. Deep-copy копирует клонированный объект и все объекты, на которые ссылается объект, рекурсивно, пока все объекты в графе не будут скопированы. Неглубокая копия (называемая мелкой, если копируются только ссылки верхнего уровня) не может делать ничего или является частью глубокой копии.

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