Вы не должны извлекать из ICloneable.
Причина в том, что когда Microsoft разрабатывала платформу .net, они никогда не указывали, должен ли Clone()метод ICloneableбыть глубоким или неглубоким клоном, поэтому интерфейс семантически нарушен, так как вызывающие абоненты не будут знать, будет ли вызов глубоким или поверхностным клонированием объекта.
Вместо этого вы должны определить свои собственные IDeepCloneable(и IShallowCloneable) интерфейсы с помощью DeepClone()(и ShallowClone()) методов.
Вы можете определить два интерфейса, один с универсальным параметром для поддержки строго типизированного клонирования, а другой без сохранения возможности слабо типизированного клонирования, когда вы работаете с коллекциями различных типов клонируемых объектов:
public interface IDeepCloneable
{
object DeepClone();
}
public interface IDeepCloneable<T> : IDeepCloneable
{
T DeepClone();
}
Что бы вы затем реализовали следующим образом:
public class SampleClass : IDeepCloneable<SampleClass>
{
public SampleClass DeepClone()
{
// Deep clone your object
return ...;
}
object IDeepCloneable.DeepClone()
{
return this.DeepClone();
}
}
Обычно я предпочитаю использовать описанные интерфейсы, а не конструктор копирования, он очень четко сохраняет намерения. Конструктор копирования, вероятно, будет считаться глубоким клоном, но это определенно не так ясно, как использование интерфейса IDeepClonable.
Это обсуждается в Руководстве по проектированию .NET Framework и в блоге Брэда Абрамса.
(Я полагаю, если вы пишете приложение (в отличие от фреймворка / библиотеки), поэтому вы можете быть уверены, что никто за пределами вашей команды не будет вызывать ваш код, это не имеет большого значения, и вы можете назначить семантическое значение "deepclone" в интерфейс .net ICloneable, но вы должны убедиться, что это хорошо задокументировано и хорошо понимается в вашей команде. Лично я бы придерживался рекомендаций по фреймворку.)