2010-08-23 6 views
10

같은 이름의 다른 파생 형식으로 기본 클래스의 속성을 재정의하려고합니다. 나는 그것의 공생 또는 generics에 의해 가능하다고 생각하지만 그것을하는 방법을 모르겠다?파생 된 형식 및 같은 이름으로 속성 재정의 C#

다음 코드는 오류 가져옵니다 나는 일의 "데이터"개체를 처리 할 때 최종 결과를 들어

Error 1 'Sun.Cache': type must be 'OuterSpace.Cache' to match overridden member 'OuterSpace.Cache'

public class OuterSpace { 
    public virtual OuterSpaceData Data {get; set;} 
    public virtual OuterSpaceAnalysis Analysis {get; set;} 
    public virtual OuterSpaceCache Cache {get; set;} 


    public class OuterSpaceData { 
     //Lots of basic Data Extraction routines eg 
     public virtual GetData(); 
    } 
    public class OuterSpaceAnalysis { 
     //Lots of Generic Analysis on Data routines eg 
     public virtual GetMean(); 
    } 
    public class OuterSpaceCache { 
     //Lots of Caches of Past Analysis Results: 
     public Dictionary<AnalysisType, List<Result>> ResultCache; 
    } 
} 

public class Sun : OuterSpace { 
    public override SunData Data {get; set;} 
    public override SunAnalysis Analysis {get; set;} 
    public override SunCache Cache {get; set;} 

    public SunData : OuterSpaceData { 
     //Routines to specific get data from the sun eg 
     public override GetData(); 
    } 

    public SunAnalysis : OuterSpaceAnalysis { 
     //Routines specific to analyse the sun: eg 
     public double ReadTemperature(); 
    } 
    public SunCache : OuterSpaceCache { 
     //Any data cache's specific to Sun's Analysis 
     public Dictionary<AnalysisType, List<Result>> TempCache; 
    } 
} 

public class Moon : OuterSpace {} etc. 

을, 나는 두 개의 데이터 개체가있을 싶지 않아 (& 상속 기본 클래스)하지만 속성을 무시하려고하면 Sun 변수가 기본 클래스와 동일한 유형이어야합니다. 예 :

Sun EarthSun = new Sun() 
EarthSun.Analyse() //The OuterSpace Analysis Saves results to Sun Cache: 

//Now try use the result: 
EarthSun.Cache[0]... 
아주 이와 유사한 대신 문자열 배열의 파생 유형

: C# Member variable overrides used by base class method

그리고이 대답이 훨씬 이해가되지 않았다 나에게 : How to override member of base class after inheritance in C++

아니면이 그게 가능하지 않다는 것을 의미합니까? Can I Override with derived types?

도움말! :) 주위에 어떤 작품?

public class OuterSpace<TCacheType> where TCacheType : OuterSpaceCache { 
    public virtual OuterSpaceData Data {get; set;} 
    public virtual OuterSpaceAnalysis Analysis {get; set;} 
    public virtual TCacheType Cache {get; set;} 


    public class OuterSpaceData { 
     //Lots of basic Data Extraction routines eg 
     public virtual GetData(); 
    } 
    public class OuterSpaceAnalysis { 
     //Lots of Generic Analysis on Data routines eg 
     public virtual GetMean(); 
    } 
    public class OuterSpaceCache { 
     //Lots of Caches of Past Analysis Results: 
     public Dictionary<AnalysisType, List<Result>> ResultCache; 
    } 
} 

public class Sun : OuterSpace<SunCache> { 
    public override SunData Data {get; set;} 
    public override SunAnalysis Analysis {get; set;} 

    public SunData : OuterSpaceData { 
     //Routines to specific get data from the sun eg 
     public override GetData(); 
    } 

    public SunAnalysis : OuterSpaceAnalysis { 
     //Routines specific to analyse the sun: eg 
     public double ReadTemperature(); 
    } 
    public SunCache : OuterSpaceCache { 
     //Any data cache's specific to Sun's Analysis 
     public Dictionary<AnalysisType, List<Result>> TempCache; 
    } 
} 

공정 경고, 완전히 컴파일되지 않은 코드를 내가 완전히 잘못 될 수 :)하지만 내가 당신을 어떻게 생각하는지에 찔린 : 당신은 공분산 경로를 찾고 있다면

+1

약간 주제에서 벗어나지 만 Sun은 일종의 OuterSpace라고 말하는 것이 합리적입니까? 여기서 어색함의 일부는 간단한 구조로 충분할 상속을 사용하는 것일 수 있습니다. –

+0

나는 제안을 환영합니까? 이것은 문제의 데모 의사 코드이며 실제 프로젝트는 매우 커서 미래를 계획하고 있습니다. – JaredBroad

+0

당신이 제공 한 샘플 구조만으로는 말하기 어렵습니다. 고려해야 할 주요 사항은 클래스를 실제로 사용하는 방법입니다. 특히 캐시, 분석 및 데이터 클래스는 기본 클래스로 액세스하는 것이 유리합니다. 분석을 조정하는 클래스가 있지만 분석 유형별로 조정이 다른 것처럼 보입니다. 그것은 저에게 더 많은 조사가 필요할 수있는 숨겨진 책임임을 시사합니다. 아직 일반 구조에 대한 유스 케이스가없는 경우에는 사용하지 않는 것이 좋습니다. 야기. –

답변

11

원하는대로 정확하게 지정할 수 없습니다.

당신은 같은 이름의 "새"속성을 만들 수 있습니다

:

public new SunData Data 
{ 
    get { return (SunData) base.Data; } 
    set { base.Data = value; } 
} 

그것은 꽤 같은 일이 아니지만, 아마 당신이받을거야만큼 가까이를.

또 다른 가능한 방법은 다음과 같습니다

public SunData SunData { get; set; } 

public override OuterSpaceData Data 
{ 
    get { return SunData; } 
    set { SunData = (SunData)value; } 
} 

이 방법의 장점은 그것이 SunData 아닌 데이터 속성에 뭔가를 넣어 불가능 보장 않는다는 것입니다. 단점은 Data 속성이 강력하게 형식화되어 있지 않으며 SunData에 정적으로 입력하려는 경우 SunData 속성을 사용해야한다는 것입니다.

기본 클래스 Data 속성에 'sealed override'를 수행하는 중간 파생 클래스를 도입하여 코드를 혼동하고 나중에 이해하기가 어렵지만 "두 가지 장점 모두"를 얻을 수있는 추한 방법이 있습니다. 새 이름으로 다른 보호 된 속성으로 리디렉션 한 다음 궁극적 인 파생 클래스에 중간 속성을 호출하는 '새'Data 속성을 추가하게합니다.그것은 정말로 추한 해킹이지만, 비록 내가 그것을 했더라도, 나는 그것을 추천하지 않을 것이다.

+1

이미 알고있는 것처럼 "새로운"속성 접근 방식은 객체가 기본 클래스로 캐스트 될 때 바람직하지 못한 부작용을 가질 수 있습니다. – kbrimington

+1

고마워, 나는 꽤 볼 수 없다 : 분석 결과가 기본 클래스에 저장되므로 SunCache Null 문제를 해결할 수 있습니까? SunCache의 추가 변수는 어떻습니까? 그들은 잃어 버릴 것인가? – JaredBroad

+0

또한 두 번째 방법에서는 데이터를 강력하게 입력합니다. 우리는 단순히 속성 호출에 대한 컴파일 타임 형식 검사가 부족합니다. – kbrimington

1

,이 같은 작업을해야합니다

0

SunData하면 ...

오 ... 원하고, 나는이, 당신이 이전, 공동 차이가 도입 할 수 있다고 생각하지 않습니다 닷넷 4.0 유일한 솔루션입니다 생각 Outer와 할당이 호환됩니다. 공간 데이터 (상속)에서 OuterSpaceData 유형을 수정할 필요가 없습니다.

+0

SunCache/SunAnalysis 특정 변수/메소드에 액세스해야합니다 (바람직하게는 필요할 때마다 캐스트하지 않아도 됨). 유형을 올바르게 설정해야한다는 의미는 아닙니다. – JaredBroad

+0

@ JaredBroad 당신이 말하는 것은 디자인 냄새가 나는 것입니다. 당신은 확실히 "절대"(매우 드문 경우처럼) 다운 캐스팅을해야합니다. 당신이 기능을 파생시키는 것 같아요 전략 패턴을보고 seprate 클래스에 일반적인 논리/기능을 배치하고 그 유형의 객체를 삽입하십시오 –

+0

제안을 주셔서 감사합니다. 인터페이스가 도움이되는 것을 볼 수 있으며 시간이 지나면 나중에 재생됩니다. http://en.wikipedia.org/wiki/Strategy_pattern#C.23 – JaredBroad

0
제네릭 확실

하지,하지만 당신은 간단한 다형성과 제한된 효과를 얻을 수

public class Sun : OuterSpace 
{ 
    void SomeInitializationMethod() 
    { 
    Data = new SunData(); 
    Analysis = new SunAnalysis(); // etc 
    } 

    } 

// You could also make casting simpler with a generic method on the base 
public T GetData<T>() 
{ 
    if (Data is T) 
    { 
    return Data as T; 
    } 
    return null; 
}; 
+0

고마워, 처음에는 비슷한 점이 있었지만 가능한 경우 코드를 통해 버려진 캐스트를 피하려고합니다. 적어도 선택된 대답 주조는 중앙 집중화되어 있습니다. : \ – JaredBroad

7

제네릭에 대해려고 시도 (SunData을 가정하는 등 데이터에서 상속). 다음 클래스는 속성 유형에 상속 규칙을 적용하는 매개 변수에 제약 조건이있는 OuterSpace에 대한 일반 기본 클래스를 제공합니다. 나는 명확성을 위해 작은 유형의 메소드를 생략했다.

public class OuterSpace<TData, TAnalysis, TCache> 
    where TData : OuterSpaceData 
    where TAnalysis : OuterSpaceAnalysis 
    where TCache : OuterSpaceCache 
{ 
    public virtual TData Data { get; set; } 
    public virtual TAnalysis Analysis { get; set; } 
    public virtual TCache Cache { get; set; } 
} 
public class OuterSpaceData { } 
public class OuterSpaceAnalysis { } 
public class OuterSpaceCache { } 

public class Sun : OuterSpace<SunData, SunAnalysis, SunCache> 
{ 
    public override SunData Data { get; set; } 
    public override SunAnalysis Analysis { get; set; } 
    public override SunCache Cache { get; set; } 
} 
public class SunData : OuterSpaceData { } 
public class SunAnalysis : OuterSpaceAnalysis { } 
public class SunCache : OuterSpaceCache { } 

이 방법의 매력은 당신이 강력한 형식의 속성 를 반환하고 그 속성의 유형에 대한 기본 상속 제약 조건을 적용 할 수있게한다는 것입니다. 이 메서드는 완전히 재정의 할 수 있습니다. 그러나 기본 클래스 구현과 관련된 문제를 피하기 위해 재정의가 필요할 수도 있습니다.

+0

이것은 꽤 보이지만 어쩌면 작동 할 수도 있지만 구현하려고 시도하고 매우 지저분 해집니다. 이 프로그램은 실제로 50-100k 길며 모든 "OuterSpace"가 나를 두려워했던 모든 유형을 재 입력해야합니다 :) 감사합니다, – JaredBroad

+0

@ Jared : 답변 해 주셔서 감사합니다. 그것은 예쁘고 일합니다. 그러나, @ stuart의 접근 방식을 사용하는 것이 적절하다는 것을 알 수 있습니다 (두 번째 것 - 가능하다면'new' 멤버 선언을 피하십시오). 그리고 특별한 방법으로 접근하기 위해 필요한 경우 타입 캐스팅을 사용하십시오. (예 :'var data = mySunDataObject.Data as SunData;). – kbrimington

+0

@ Jared :'Sun' 클래스의 3 가지 오버라이드는 getter와 setter에서 다른 동작을하려는 경우에만 필요합니다. 예제에서 보았던 plain-ol '빈 getter 및 setter의 경우 재정의를 제거하고 동일한 효과를 얻을 수 있습니다. – kbrimington