2013-06-05 8 views
0

나는 몇 가지 코드를 작성했으며, 두 개의 클래스 (즉, 물고기와 포유류는 아래에 있음)가 동일한 패턴을 가지고 있기 때문에 제네릭과 합산하기로 결정했다.ICloneable을 구현해야합니까?

문제는 내가 기본 클래스 부분에서 생성자를 복사 할 필요가있다.

또한,이 생성자 (0-매개 변수)들 기본 있지 않기 때문에 새로운() 제약 (CS0304)을 사용하여 고정 할 수 없습니다.

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().Foo1George.Foo1과 동일한 인스턴스를 참조해야합니다. 필드 Foo2가 변경 가능한 상태가 아니라 정체성을 캡슐화 경우

George.Clone().Foo2George.Foo2과 같은 상태가 초기화되는 새로운 객체를 참조해야합니다.

필드 Foo3은 가변 상태 나 신원 [도를 캡슐화하는 경우, 즉 신원이 아닌 불변의 상태 만] 인 경우 George.Clone().Foo3George.Foo3을 참조하거나 동일한 상태의 새 객체 또는 동일한 상태의 다른 편리한 객체를 참조 할 수 있습니다.

Foo4 필드가 변경 가능한 상태와 ID를 모두 캡슐화하는 경우 Clone 메서드를 사용하여 해당 유형의 인스턴스를 의미있게 복제 할 수 없습니다.

신원, 변경 가능한 상태, 둘 다 또는 둘 다 캡슐화하는 것에 대해 다른 저장 위치 유형이있는 경우 참조 유형 필드 나 다른 저장소 유형으로 캡슐화 된 참조 저장 영역이 있기 때문에 심층 대 얕은 구분은 거의 없습니다. 타입은 위의 규칙을 재귀 적으로 적용하여 복제해야합니다. 두 객체가 다른 객체의 가변성 상태를 의미있는 방법으로 캡슐화 할 수 없기 때문에 올바르게 생성 된 객체의 경우 반복적 인 순환이 발생할 수 없습니다. 불행하게도 타입 시스템에는 이러한 구분이 없으므로 임시 복제 방법을 구현하거나 또는 속성을 사용하여 수행해야 할 작업을 결정하는 복제 방법을 구현하고 하드 코딩 된 동작을 사용하여 내장 된 특별한 표시자를 포함하지 않는 .NET 유형.

0

기본 기본 생성자가 어쨌든 호출됩니다. 이 질문에 대한 당신의 문제를 만들 수 있기 때문에

당신은 깊은 또는 얕은 사본입니다 ICloneable을 구현할 필요가 없습니다. 그러나 어쨌든 복제 패턴을 따를 수 있습니다 (다르게 만 호출하십시오). How to Implement ICloneable Interface in Derivable Classes in .NET : 여기

함께 또는 ICloneable 인터페이스없이 복제 기능을 구현하는 당신을 이끌 수있는 자원이다.

아이디어는 기본 생성자 외에도 보호 된 복사본 생성자를 만드는 것입니다. 그러면 new() 제약 조건을 유지하면서 필요한 경우 파생 클래스에 기본 및 파생 내용을 복제하는 옵션을 제공 할 수 있습니다.

+0

상속 가능한 클래스에는 'MemberwiseClone'에 연결되지 않는 복제 멤버가 없어야합니다. 그렇지 않으면 파생 클래스의 인스턴스에서 'Clone'을 호출하면 파생 클래스를 오버라이드하지 않으므로 잘못된 유형의 인스턴스가 생성됩니다. – supercat

+0

@supercat 모든 가상 메소드의 경우가 아닙니까? 잠시 ICloneable 인터페이스를 잊어 버리고 자신의 복제 메커니즘 (예 : Copy 메소드)을 구현했다고 가정 해보십시오. 이 메소드는 기본적으로 기본 유형에 대한 참조를 반환합니다. 상속자는이를 상속해야합니다. 그렇지 않으면 제대로 작동하지 않습니다. MemberwiseClone을 사용한다고해서 deep cloning 문제는 해결되지 않습니다. –

+0

복제 멤버가'MemberwiseClone' (선호되는 보호 가상 메소드를 사용하여 연결) 체인을 구성하고 파생 클래스가 자체적으로 소유하고있는 변경 가능한 객체를 생성하지 않으면 부모의 복제 방법이 제대로 작동하여 파생 된 유형의 인스턴스 그렇지 않으면 모든 * 파생 클래스가 부모 메서드의 복사 생성자에 대한 체인 일 경우에도 복제 메서드 재정의를 정의해야합니다. 그렇게하지 않으면 컴파일러 진단이 발생하지 않습니다. – supercat