문제

이것이 이상한 일인지 아닌지, 또는 코드 냄새가 어떻게 냄새가 있는지 확실하지 않습니다 ... 그러나 "CAST"의 방법이 있는지 궁금했습니다. 파생 유형의 형태에 대한 기본 유형. 파생 된 유형이 부모가 제공하지 않는 추가 기능이 있기 때문에 이것이 의미가 없다는 것을 알고 있습니다. 그러나 이것을 할 방법이 있습니까? 여기에 코드 예제가 있습니다.

public class SomeBaseClass {
    public string GetBaseClassName {get;set;}
    public bool BooleanEvaluator {get;set;}
}

public class SomeDerivedClass : SomeBaseClass {
    public void Insert(SqlConnection connection) {
          //...random connection stuff
          cmd.Parameters["IsItTrue"].Value = this.BooleanEvalutar;
          //...
    }
}

public static void Main(object[] args) {
    SomeBaseClass baseClass = new SomeBaseClass();
    SomeDerivedClass derClass = (SomeDerivedClass)baseClass; 
    derClass.Insert(new sqlConnection());
}

나는 이것이 구피처럼 보이지만 이런 종류의 것을 성취 할 수있는 방법이 있습니까?

도움이 되었습니까?

해결책

"관리 된"언어에서는 소리가 나지 않습니다. 이것은 다운 캐스팅, 정확히 설명한 이유가 있기 때문에 (하위 클래스는 기본 클래스 이상을 제공합니다. 특정 계층 구조에 대해 유사한 동작을 실제로 원한다면 기본 유형을 프로토 타입으로 취할 파생 유형에 생성자를 사용할 수 있습니다.

간단한 케이스 (추가 상태가없는보다 구체적인 유형)를 처리 한 반사로 무언가를 만들 수 있습니다. 일반적으로 문제를 피하기 위해 재 설계하십시오.

편집 : WOOPS, 기본/파생 유형간에 변환 연산자를 쓸 수 없습니다. Microsoft의 이상한 것은 자신을 대적하기 위해 "당신을 보호"하려고합니다. 아, 적어도 그들은 태양만큼 나쁘지 않습니다.

다른 팁

상속 대신 구성을 시도하십시오!

SomeBaseClass의 인스턴스를 언젠가는 언젠가는 더 이상 기본 클래스를 도출하지 않으며 이름이 바뀌어야합니다)

public class BooleanHolder{       
    public bool BooleanEvaluator {get;set;}
}

public class DatabaseInserter{
    BooleanHolder holder;

    public DatabaseInserter(BooleanHolder holder){
        this.holder = holder;
    }

    public void Insert(SqlConnection connection) {
          ...random connection stuff
          cmd.Parameters["IsItTrue"].Value = holder.BooleanEvalutar;
          ...
    }
}

public static void Main(object[] args) {
    BooleanHolder h = new BooleanHolder();
    DatabaseInserter derClass = new DatabaseInserter(h);
    derClass.Insert(new sqlConnection);
}

체크 아웃 http://www.javaworld.com/javaworld/jw-11-1998/jw-11-techniques.html (페이지 3) :

구성 조성을 통한 코드 재사용은 애플이 과일의 Peel () 구현을 재사용하는 대안적인 방법을 제공합니다. 과일을 연장하는 대신 Apple은 과일 인스턴스를 참조하고 단순히 과일에서 Peel ()을 호출하는 자체 껍질 () 방법을 정의 할 수 있습니다.

개인적으로 나는이 경우 상속을 사용하는 번거 로움이 있다고 생각하지 않습니다. 대신 생성자의 기본 클래스 인스턴스를 전달하고 멤버 변수를 통해 액세스하십시오.

private class ExtendedClass //: BaseClass - like to inherit but can't
{
    public readonly BaseClass bc = null;
    public ExtendedClass(BaseClass b)
    {
        this.bc = b;
    }

    public int ExtendedProperty
    {
        get
        {
        }
    }
}

다운 캐스팅은 파생 된 클래스의 객체가 있지만 기본 클래스 유형의 참조로 참조되는 경우, 어떤 이유로 든 파생 된 클래스 유형 참조로 다시 참조하기를 원합니다. 다시 말해, 이전 업 캐스트의 효과를 뒤집기 위해 다운 캐스트 할 수 있습니다. 그러나 파생 클래스 유형의 참조로 참조 된 기본 클래스의 객체는 가질 수 없습니다.

나는 이것을 추천한다고 말하는 것이 아닙니다. 그러나 기본 클래스를 JSON 문자열로 바꾸고 파생 클래스로 변환 할 수 있습니다.

SomeDerivedClass layer = JsonConvert.DeserializeObject<SomeDerivedClass>(JsonConvert.SerializeObject(BaseClassObject));

아니요, 이것은 불가능합니다. C#과 같은 관리 언어에서는 작동하지 않습니다. 컴파일러가 통과하더라도 런타임은 허용되지 않습니다.

당신은 이것이 바보처럼 보인다고 스스로 말했습니다.

SomeBaseClass class = new SomeBaseClass();
SomeDerivedClass derClass = (SomeDerivedClass)class; 

그러니 스스로에게 물어보세요 class 실제로 인스턴스 SomeDerivedClass? 아니요, 변환은 의미가 없습니다. 변환 해야하는 경우 SomeBaseClass 에게 SomeDerivedClass, 그런 다음 생성자 또는 변환 방법과 같은 일종의 변환을 제공해야합니다.

그래도 클래스 계층 구조에 약간의 작업이 필요한 것처럼 들립니다. 일반적으로 그렇지 않아야합니다 기본 클래스 인스턴스를 파생 클래스 인스턴스로 변환 할 수 있습니다. 일반적으로 기본 클래스에 적용되지 않는 데이터 및/또는 기능이 있어야합니다. 파생 클래스 기능이 적용되는 경우 모두 기본 클래스의 사례는 기본 클래스로 롤업하거나 기본 클래스 계층의 일부가 아닌 새로운 클래스로 가져와야합니다.

C# 언어는 그러한 연산자를 허용하지 않지만 여전히 글을 쓸 수 있으며 작동합니다.

[System.Runtime.CompilerServices.SpecialName]
public static Derived op_Implicit(Base a) { ... }

[System.Runtime.CompilerServices.SpecialName]
public static Derived op_Explicit(Base a) { ... }

예 - 이것은 코드 냄새이며, 상속 체인이 고장났다는 사실을 거의 못 박았습니다.

나의 추측 (제한된 샘플에서)는 당신이 오히려 파생 된 클래스가 somebaseclass 인스턴스에서 작동한다는 것입니다. a "파생 된 클래스가 아닌 somebaseclass" a somebaseclass ". 이것은"상속에 대한 호의 구성 "으로 알려져 있습니다.

다른 사람들이 지적했듯이, 당신이 제안하는 캐스팅은 실제로 불가능합니다. 아마도 경우가 될 것입니다 데코레이터 패턴(Head First Extract)를 도입 할 수 있습니까?

현재 기본 클래스와 파생 클래스가 구현 될 것이라는 인터페이스에 대해 생각해 보셨습니까? 나는 당신이 왜 이런 식으로 구현하는지에 대한 세부 사항을 모르지만 효과가있을 수 있습니다.

이것을 다운 캐스팅이라고 불리며 "안전한"버전을 사용하라는 Seldaek의 제안은 사운드입니다.

여기에 꽤 괜찮습니다 코드 샘플을 사용한 설명.

파생 된 클래스가 가지고있는 "추가"를 어떻게 얻을 수 있기 때문에 이것은 불가능합니다. 컴파일러는 당신이 그것을 인스턴스화 할 때 DevivedClass2가 아니라는 것을 의미한다는 것을 어떻게 알 수 있습니까?

나는 당신이 실제로 찾고있는 것이 공장 패턴 또는 이와 유사하다고 생각하므로 인스턴스화되는 명시 적 유형을 실제로 알지 못하고 개체를 인스턴스화 할 수 있습니다. 예에서 "삽입"메소드를 갖는 것은 인스턴스가 공장이 구현을 반환하는 인터페이스가됩니다.

왜 아무도 이것을 말하지 않았는지 모르고 나는 무언가를 놓치고 있을지 모르지만 당신은 키워드를 사용할 수 있으며 if 문을 사용해야하는 경우 IF를 사용해야합니다.

SomeDerivedClass derClass = class as SomeDerivedClass; //derClass is null if it isnt SomeDerivedClass
if(class is SomeDerivedClass)
    ;

-편집하다- 나는 오래 전에이 질문을했다

나는 최근에 더 많은 속성을 넣기 위해 파생 된 유형의 간단한 DTO를 확장해야했습니다. 그런 다음 내부 데이터베이스 유형에서 DTO에 이르기까지 내가 가진 일부 변환 로직을 재사용하고 싶었습니다.

내가 해결 한 방식은 DTO 클래스에서 빈 생성자를 시행하고 다음과 같이 사용하는 것이 었습니다.

class InternalDbType {
    public string Name { get; set; }
    public DateTime Date { get; set; }
    // Many more properties here...
}

class SimpleDTO {
    public string Name { get; set; }
    // Many more properties here...
}

class ComplexDTO : SimpleDTO {
    public string Date { get; set; }
}

static class InternalDbTypeExtensions {
    public static TDto ToDto<TDto>(this InternalDbType obj) where TDto : SimpleDTO, new() {
        var dto = new TDto {
            Name = obj.Name
        }
    }
}

그런 다음 복잡한 DTO로 변환 할 때 간단한 DTO에서 변환 로직을 재사용 할 수 있습니다. 물론, 나는 다른 방식으로 복잡한 유형의 속성을 채워야 할 것이지만, 간단한 DTO의 많은 속성으로 인해 이것은 실제로 IMO를 단순화합니다.

그것은 효과가 없습니다. 컴파일 오류로 연결된 도움말 페이지를 살펴보십시오.

가장 좋은 솔루션은 여기에서 공장 방법을 사용하는 것입니다.

많은 답변이 지적했듯이, 당신은 완전히 의미가있는 다운 캐스트 할 수 없습니다.

그러나 귀하의 경우에는 SomeDerivedClass '누락 된'속성이 없습니다. 따라서 다음과 같은 확장 방법을 만들 수 있습니다.

public static T ToDerived<T>(this SomeBaseClass baseClass) 
    where T:SomeBaseClass, new()
{
    return new T()
    {
        BooleanEvaluator = baseClass.BooleanEvaluator,
        GetBaseClassName = baseClass.GetBaseClassName
    };
}

그래서 당신은 캐스팅을하지 않고 변환합니다.

SomeBaseClass b = new SomeBaseClass();
SomeDerivedClass c = b.ToDerived<SomeDerivedClass>();

이것은 기본 클래스의 모든 데이터가 읽을 수 있고 쓰기 쉬운 속성의 형태 인 경우에만 실제로 작동합니다.

C ++는 생성자를 사용하여 처리합니다. C ++ 타입 캐스팅. 나에게 감독처럼 보인다. 많은 분들이 프로세스가 추가 속성으로 무엇을하는지에 대한 문제를 제기했습니다. 대답 할 것입니다. 컴파일러는 프로그래머가 속성을 설정하지 않을 때 파생 클래스를 생성 할 때 무엇을합니까? C ++와 비슷한이 상황을 처리했습니다. 기본 클래스를 차지하는 생성자를 작성한 다음 생성자에 속성을 수동으로 설정합니다. 이것은 파생 클래스에서 변수를 설정하고 상속을 깨는 것보다 확실히 바람직합니다. 또한 결과 코드가 더 깨끗해질 것이라고 생각하기 때문에 공장 방법보다 선택할 것입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top