복제할 수 없는 이유는 무엇입니까?
제네릭 제품이 사용되는 특별한 이유가 있습니까?ICloneable<T>
존재하지 않습니까?
제가 무언가를 복제할 때마다 캐스팅할 필요가 없다면 훨씬 더 편할 것입니다.
에도 (하는 + - Andrey가 (가의동제 +1) 외에답 - 언제 때ICloneable
완료되었습니다. 또한 공개하기 위해 명시적인 구현을 선택할 수 있습니다.Clone()
입력한 개체 반환:
public Foo Clone() { /* your code */ }
object ICloneable.Clone() {return Clone();}
▁a▁▁issue▁second다 두 번째 문제가 있습니다.ICloneable<T>
상속 재산
내가 가지고 있는 경우:
public class Foo {}
public class Bar : Foo {}
그리고 나는 구현했습니다.ICloneable<T>
그럼 제가 구현할까요?ICloneable<Foo>
?ICloneable<Bar>
많은 동일한 인터페이스를 빠르게 구현하기 시작합니다.요?그리고 정말 그렇게 나쁜가요?
ICloneable은 결과가 딥 복사인지 얕은 복사인지 지정하지 않기 때문에 현재 불량 API로 간주됩니다.이것이 그들이 이 인터페이스를 개선하지 않는 이유라고 생각합니다.
당신은 아마 형식적인 복제 확장 방법을 할 수 있지만, 확장 방법의 우선 순위가 원래보다 낮기 때문에 다른 이름이 필요할 것 같습니다.
저는 당신이 인터페이스를 구현하는 것 외에 정확히 무엇을 할 것인지 묻고 싶습니다.인터페이스는 일반적으로 캐스트할 때만 유용합니다(즉, 이 클래스가 지원합니까).'IBar') 또는 이를 사용하는 매개 변수 또는 설정자가 있습니다(즉, 'I'를 사용함).IC 복제가 가능한 상태에서 전체 프레임워크를 검토한 결과 구현 이외의 용도를 찾을 수 없었습니다.또한 '실제 환경'에서 이를 구현하는 것 외에 다른 기능을 하는 용도(접속 가능한 최대 60,000개 앱)도 찾을 수 없었습니다.
이제 '복제 가능한' 개체를 구현할 패턴을 적용하려면 이 방법을 사용하는 것이 좋습니다.또한 "복제"가 사용자에게 정확히 어떤 의미인지(깊거나 얕음) 결정할 수 있습니다.그러나 이 경우에는 우리(BCL)가 이를 정의할 필요가 없습니다.추상화로 입력된 인스턴스를 관련 없는 라이브러리 간에 교환해야 할 경우에만 BCL에서 추상화를 정의합니다.
David Kean (BCL 팀)
"왜"라는 질문은 불필요하다고 생각합니다.많은 인터페이스/클래스/등이 있습니다.매우 유용하지만 의 일부는 아닙니다.NET Framework 기본 라이브러리.
하지만 주로 당신이 직접 할 수 있습니다.
public interface ICloneable<T> : ICloneable {
new T Clone();
}
public abstract class CloneableBase<T> : ICloneable<T> where T : CloneableBase<T> {
public abstract T Clone();
object ICloneable.Clone() => return this.Clone();
}
public abstract class CloneableExBase<T> : CloneableBase<T> where T : CloneableExBase<T> {
protected abstract T CreateClone();
protected abstract void FillClone(T clone);
public override T Clone() {
T clone = this.CreateClone();
if (clone is null ) {
throw new NullReferenceException( "Clone was not created." );
}
this.FillClone(clone);
return clone
}
}
public abstract class PersonBase<T> : CloneableExBase<T> where T : PersonBase<T> {
public string Name { get; set; }
protected override void FillClone( T clone ) {
clone.Name = this.Name;
}
}
public sealed class Person : PersonBase<Person> {
protected override Person CreateClone() => return new Person();
}
public abstract class EmployeeBase<T> : PersonBase<T> where T : EmployeeBase<T> {
public string Department { get; set; }
protected override void FillClone(T clone) {
base.FillClone(clone);
clone.Department = this.Department;
}
}
public sealed class Employee : EmployeeBase<Employee> {
protected override Employee CreateClone() => return new Employee();
}
필요한 경우 인터페이스를 직접 작성하는 것은 매우 쉽습니다.
public interface ICloneable<T> : ICloneable
where T : ICloneable<T>
{
new T Clone();
}
최근에 "왜 물체를 복사하는 것이 끔찍한 일인가?"라는 기사를 읽었습니다.이 질문은 추가적인 확증이 필요하다고 생각합니다.여기에 있는 다른 답변은 좋은 조언을 제공하지만, 여전히 답변이 완전하지 않습니다. - 왜 안 되죠?ICloneable<T>
?
사용.
이를 구현하는 클래스가 있습니다.이전에 당신이 원하는 방법이 있었을 것입니다.
ICloneable
이제 그것은 받아들여지기 위해 일반적이어야 합니다.ICloneable<T>
편집해야 합니다.그러면, 당신은 물체가 어떤 물체인지 확인할 수 있는 방법을 얻을 수 있었을 것입니다.
is ICloneable
?그럼 어쩌라는 거야?은 할 수 요.is ICloneable<>
그리고 컴파일 형식에서 객체의 유형을 모르기 때문에 메소드를 제네릭으로 만들 수 없습니다.첫번째 진짜 문제.그래서 당신은 두 가지를 모두 가져야 합니다.
ICloneable<T>
그리고.ICloneable
후자를 구현하는 전자따라서 구현자는 두 가지 방법을 모두 구현해야 합니다.object Clone()
그리고.T Clone()
. 아요니, 니다합으로 즐깁니다. 우리는 이미 충분히 즐겼습니다.IEnumerable
.이미 지적했듯이 상속의 복잡성도 있습니다.공분산이 이 문제를 해결하는 것처럼 보일 수 있지만 파생된 유형은 다음을 구현해야 합니다.
ICloneable<T>
자체 유형이지만 동일한 서명(= 매개 변수, 기본적으로)을 가진 방법이 이미 있습니다. - 더Clone()
새로운 으로 만드는 의미가 없으며, 생성할 때 을 잃게 .ICloneable<T>
그래서 추가합니다.new
클래스의 기본 클래스를 을 잊지 마세요.Clone()
모든 파생 클래스에 기본 는 (즉, 모클메에서동일객한드반체대모에는는해메구드환현소이하균)이어야 합니다.virtual
은 둘 다 할 수 .override
그리고.new
동일한 서명을 가진 메서드입니다.첫 번째 키워드를 선택하면 추가할 때 원하는 목표를 잃게 됩니다.ICloneable<T>
두 번째를 선택하면 인터페이스 자체가 깨지고, 동일한 작업을 수행해야 하는 방법이 서로 다른 개체를 반환합니다.포인트
너는 원한다
ICloneable<T>
편안함을 위해, 그러나 편안함은 인터페이스가 설계된 것이 아니며, 그들의 의미는 (일반적으로 OOP) 객체의 행동을 통합하는 것입니다(그러나 C#에서는 외부 행동, 예를 들어 방법과 특성을 통합하는 것으로 제한됩니다).만약 첫 번째 이유가 아직 당신을 납득시키지 못했다면, 당신은 반대할 수 있습니다.
ICloneable<T>
복제 방법에서 반환되는 형식을 제한하기 위해 제한적으로 작동할 수도 있습니다.하만지, 형는프래는머를 할 수 .ICloneable<T>
여기서 T는 이를 구현하는 유형이 아닙니다.따라서 제한을 달성하기 위해 일반 매개 변수에 적절한 제약 조건을 추가할 수 있습니다.
public interface ICloneable<T> : ICloneable where T : ICloneable<T>
실히없는것더보제다니입한적다확▁without▁one다가 없는 보다 더 입니다.where
당신은 여전히 T가 인터페이스를 구현하는 유형이라는 것을 제한할 수 없습니다.ICloneable<T>
이를 구현하는 다양한 유형).수 의 알시피달, 이목도원수성다없니할습었차래조적다원(▁youthe수▁couldn다없니▁original습었▁this▁purpose달,'래▁(▁even▁achieved성▁be)
ICloneable
이 경우에도 실패합니다. 어떤 인터페이스도 구현 클래스의 동작을 진정으로 제한할 수 없습니다.
보시다시피, 일반 인터페이스를 만드는 것은 완전히 구현하기 힘들 뿐만 아니라 정말 불필요하고 쓸모가 없다는 것을 증명합니다.
하지만 다시 질문으로 돌아가서, 여러분이 진정으로 원하는 것은 물체를 복제할 때 편안함을 갖는 것입니다.두 가지 방법이 있습니다.
추가 방법
public class Base : ICloneable
{
public Base Clone()
{
return this.CloneImpl() as Base;
}
object ICloneable.Clone()
{
return this.CloneImpl();
}
protected virtual object CloneImpl()
{
return new Base();
}
}
public class Derived : Base
{
public new Derived Clone()
{
return this.CloneImpl() as Derived;
}
protected override object CloneImpl()
{
return new Derived();
}
}
이 솔루션은 사용자에게 편안함과 의도된 동작을 모두 제공하지만 구현하기에도 너무 오래 걸립니다.현재 유형을 반환하는 "편안한" 방법을 원하지 않는 경우에는 그냥 사용하는 것이 훨씬 쉽습니다.public virtual object Clone()
.
이제 "궁극적인" 솔루션을 살펴보겠습니다. C#에서 진정으로 편안함을 제공하는 것은 무엇입니까?
확장 메서드!
public class Base : ICloneable
{
public virtual object Clone()
{
return new Base();
}
}
public class Derived : Base
{
public override object Clone()
{
return new Derived();
}
}
public static T Copy<T>(this T obj) where T : class, ICloneable
{
return obj.Clone() as T;
}
현재 복제 메소드와 충돌하지 않도록 복사라는 이름입니다(컴파일러는 확장 메소드보다 형식 자체의 선언 메소드를 선호합니다).그class
속도에 대한 제약이 있습니다(Null 확인 등이 필요하지 않음).
나는 이것이 왜 만들지 않는 이유를 명확히 하기를 바랍니다.ICloneable<T>
그러나 다음을 구현하지 않는 것이 좋습니다.ICloneable
조금도.
큰 문제는 그들이 T를 같은 클래스로 제한할 수 없었다는 것입니다.예를 들어 다음과 같은 작업을 수행할 수 없습니다.
interface IClonable<T>
{
T Clone();
}
class Dog : IClonable<JackRabbit>
{
//not what you would expect, but possible
JackRabbit Clone()
{
return new JackRabbit();
}
}
다음과 같은 매개 변수 제한이 필요합니다.
interfact IClonable<T> where T : implementing_type
아주 좋은 질문입니다...하지만 당신은 당신만의 것을 만들 수 있습니다.
interface ICloneable<T> : ICloneable
{
new T Clone ( );
}
Andrey는 그것이 나쁜 API로 간주된다고 말하지만, 나는 이 인터페이스가 더 이상 사용되지 않는다는 것을 듣지 못했습니다.그렇게 되면 수많은 인터페이스가 깨지고...복제 방법은 얕은 복사를 수행해야 합니다.개체가 전체 복사본도 제공하는 경우 오버로드된 클론(bool deep)을 사용할 수 있습니다.
편집: 개체를 "복제"하기 위해 사용하는 패턴은 생성자에서 프로토타입을 전달합니다.
class C
{
public C ( C prototype )
{
...
}
}
이렇게 하면 잠재적인 중복 코드 구현 상황이 제거됩니다.BTW, ICloneable의 한계에 대해 이야기하자면, 얕은 클론 또는 깊은 클론 또는 부분적으로 얕은/부분적으로 깊은 클론을 수행할지 여부는 정말로 개체 자체에 달려 있지 않습니까?물건이 의도한 대로 작동하는 한 우리가 정말 신경을 써야 할까요?경우에 따라 양호한 클론 구현에는 얕은 클로닝과 깊은 클로닝이 모두 포함될 수 있습니다.
언급URL : https://stackoverflow.com/questions/536349/why-no-icloneablet
'programing' 카테고리의 다른 글
Bash 어레이에 값이 포함되어 있는지 확인합니다. (0) | 2023.05.05 |
---|---|
mongoose를 사용하여 컬렉션에 ID가 있는지 확인합니다. (0) | 2023.05.05 |
WPF textBox에 새 줄을 추가하지 않음을 입력합니다. (0) | 2023.05.05 |
크기 조정 후 확장기의 내용에 맞게 WPF 창의 크기를 유지하는 방법 (0) | 2023.05.05 |
LINQ: SingleOrDefault를 사용할 때와필터링 기준이 있는 FirstOrDefault() (0) | 2023.05.05 |