2013-06-05 3 views
0

Я написал несколько кодов и обнаружил, что два класса (а именно, рыба и млекопитающие ниже) имеют один и тот же шаблон, поэтому я решил подытожить дженерики.Должен ли я выполнять ICloneable?

Проблема в том, что мне нужна копия конструктора из базы класс.

Кроме того, это невозможно устранить с помощью ограничений new() (CS0304), поскольку конструкторы не являются стандартными (0-параметрами).

Я пишу это, потому что мне сказали, что реализация ICloneable не является хорошей практикой.

public class OneHeart {...} 
public class TwoHeart {...} 

public class Animal<TyHeart> /* : ICloneable ?*/ { 
    public Animal(TyHeart heart) { 
     if(heart==null) throw new ArgumentNullException(); 
     Heart = heart; 
    } 
    public Heart { get; set; } 
} 
public class Fish : Animal<OneHeart> { 
    public Fish(OneHeart heart) : base(heart) {} 
    public Fish(Fish fish) : base(fish.Heart) {} // copy ctor but no use? 
} 
public class Mammal : Animal<TwoHeart> { 
    public Mammal(TwoHeart heart, Organ lung) : base(heart) {Lungs=lung;} 
    public Mammal(Mammal mammal) : base(mammal.Heart) {Lungs=mammal.Lung;} 
    public Organ Lungs {get; set;} // Mammal-only member:) 
} 
// The Zoo collects animals of only one type: 
public class Zoo<TyHeart, TyAnimal> : LinkedList<TyAnimal> 
    where TyAnimal : Animal<TyHeart> { 
    public Zoo() : base() {} 
    public Zoo(Zoo<TyHeart, TyAnimal> srcZoo) { 
     foreach(var animal in srcZoo) { 
      // CS0304 compile error: 
      base.AddLast(new TyAnimal(animal)); 
     } 
    } 
    ... 
} 

рыба и млекопитающие являются только классами, полученных от животных и

Я знаю, они оба реализовать конструкторы копирования.

EDIT: не требуется глубокая копия.

(Типы) Сердца и легкие одноэлементные и распределяются между животными/рыбой/млекопитающими.

ответ

1

Проблема с внедрением ICloneable заключается в том, что место хранения (поле, переменная, интервал массива и т. Д.) Изменяемого ссылочного типа может использоваться для инкапсуляции идентификатора, изменяемого состояния, обоих или ни одного, но ни .NET, ни любой из его языков включает в себя любое стандартное соглашение, указывающее, какое из вышеперечисленных данных должно быть инкапсулировано.

Если поле Foo1 инкапсулирует идентичность, но не изменяет состояние, то George.Clone().Foo1 следует ссылаться на тот же экземпляр, что и George.Foo1.

Если поле Foo2 инкапсулирует изменчивое состояние, но не идентично, то George.Clone().Foo2 должно ссылаться на новый объект, который инициализирован таким же состоянием, как George.Foo2.

Если поле Foo3 инкапсулирует ни изменяемое состояние, ни идентичность [т.е. только неизменяемое состояние, отличное от идентификатора], то George.Clone().Foo3 может ссылаться на George.Foo3, новый объект с тем же состоянием или любой другой удобный объект с тем же состоянием.

Если поле Foo4 инкапсулирует как изменяемое состояние, так и идентификатор, экземпляры этого типа не могут быть объективно клонированы с использованием метода Clone.

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

0

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

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

Вот ресурс, который поможет вам внедрить средство клонирования с интерфейсом ICloneable или без него: How to Implement ICloneable Interface in Derivable Classes in .NET.

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

+0

Наследуемые классы не должны содержать элементы клонирования, которые не привязаны к 'MemberwiseClone'. В противном случае вызов «Clone» в экземпляре производного класса, который не переопределяет его, приведет к экземпляру неправильного типа. – supercat

+0

@supercat Не так ли в случае со всеми виртуальными методами? Забудьте об интерфейсе ICloneable на мгновение и представьте, что вы реализовали свой собственный механизм клонирования (например, метод копирования). Этот метод, естественно, вернет ссылку на базовый тип. Любой наследник должен будет переопределить его или он не будет работать правильно. Опора на MemberwiseClone не решает проблему глубокого клонирования. –

+0

Если элементы клонирования образуют цепочку, которая возвращается к 'MemberwiseClone' [предпочтительно привязана с использованием защищенного виртуального метода], а производный класс не создает никаких собственных собственных изменяемых объектов, метод клонирования родителя будет работать правильно, чтобы создать экземпляр производного типа. В противном случае * каждый * производный класс должен будет определить переопределение метода клонирования, даже если единственное, что он делает, это цепочка к конструктору копии родителя, и отказ сделать это не приведет к диагностике компилятора - просто поломка. – supercat

Смежные вопросы