2012-01-12 2 views
1

나는 다음과 같은 클래스가 :업 캐스팅 도우미 방법?

class Alpha 
{ 
} 
class Beta : Alpha 
{ 
} 
class Gamma : Beta 
{ 
} 
class Epsilon : Beta 
{ 
} 

을 그리고 매개 변수로 데리고 어디 몇 가지 방법이 있습니다

void Receiver(Gamma gamma); 
void Receiver(Epsilon epsilon); 
void Receiver(Beta beta); 
void Receiver(Alpha alpha); 

내가 여기 조금 특별한 뭔가가 필요합니다.
모든 메서드에 Alpha 개체를 전달할 수 있기를 원하지만 Beta에서 상속되는 형식의 개체를받을 수있는 void Receiver(Beta beta);과 같은 메서드를 사용하고 싶지 않습니다 (즉, 최악의 경우 Exception을 발생시킵니다. Gamma 또는 Epsilon 개체가 전달됩니다.

을 나는 가장 충분한 제네릭 방식으로이를 구현 할 수 있습니까?

가 내가 처음 부분에 대한 생각 가

, 내가 upcasting을 위해 할 수있는 방법이 있어야합니다, 같은 예 :

class Alpha 
{ 
    public T Upcast<T>() where T : Alpha 
    { 
     // somehow return a T 
    } 
} 

여기에있는 문제는 모든 레벨에서 작동하도록하고 싶습니다. 예를 들어 "업 캐스팅"을 할 수 있기를 원합니다. Beta도 있습니다.

두 번째 부분은 내가 필요한 형식 위에있는 개체를 전달하기 때문에 더 쉬워야합니다.

때문에 이런 일이 충분해야합니다

void Receiver(Epsilon epsilon) 
{ 
    // if epsilon inherits from Epsilon, throw. 
} 

당신이 내 문제의 첫 번째 부분으로 나를 도와 드릴까요? 감사!

+11

매개 변수로'Base'를 받아들이고'Derived'와 함께 작동하지 않는 메소드가 있다면 클래스 디자인이 잘못되었습니다. 그것이 당신이 고쳐야 할 것입니다. – Jon

+0

이것은 리플렉션을 사용하여 쿼리 문자열 매개 변수로 속성을 구문 분석하는 특수한 경우를위한 것입니다. 파생 클래스를 수용하고 싶지는 않습니다. 해당 API 호출에 잘못된 쿼리 문자열 매개 변수가 발생하는 속성을 포함 할 수 있기 때문입니다. – bevacqua

+0

나는 모든 것이'봉인되어야한다 '고해도 나는 당신의 요점을 알고있다. 그러나 여전히 나에게 중요한 것은 기막힌 방법이다. – bevacqua

답변

1

당신은 주어진 종류를 해결할 수있는 코드로 어려움을 겪고 것 같다 있지만 하위 유형이 제대로 처리 할 신뢰할 수 없습니다. 이것은 일반적으로 많은 OOP 원칙을 위반하는 것으로, 그 중 하나가 LSP이거나 Liskov Substitution Principle입니다.

이 문제를 해결하기위한 수단으로 visitor pattern을 고려할 수도 있습니다. 사소한 수정을 통해 이미 가지고있는 것과 매우 가깝습니다! 패턴이 강요 당하기보다는 코드에서 나타날 때 좋습니다.

귀하의 void Receiver 메소드는 본질적으로 이미 방문자 구현이므로, 이름을 변경하고 인터페이스를 만들어 보겠습니다.

interface IVisitor 
{ 
    void Visit(Gamma gamma); 
    void Visit(Epsilon epsilon); 
    void Visit(Beta beta); 
    void Visit(Alpha alpha); 
} 

각 요소 유형의 처리를 처리하는 클래스는 해당 인터페이스를 구현하기 만하면됩니다.

class Visitor : IVisitor 
{ 
    public void Visit(Gamma gamma) { Console.WriteLine("Visiting Gamma object"); } 
    public void Visit(Epsilon epsilon) { Console.WriteLine("Visiting Epsilon object"); } 
    public void Visit(Beta beta) { Console.WriteLine("Visiting Beta object"); } 
    public void Visit(Alpha alpha) { Console.WriteLine("Visiting Alpha object"); } 
} 

그런 다음 각 요소 유형도 간단하고 공통 인터페이스

interface IElement { void Accept(IVisitor visitor); } 

class Alpha : IElement 
{ 
    public virtual void Accept(IVisitor visitor) 
    { 
     visitor.Visit(this); 
    } 
} 

class Beta : Alpha 
{ 
    public override void Accept(IVisitor visitor) 
    { 
     visitor.Visit(this); 
    } 
} 

// etc. 
을 구현해야

(엄밀히 말하면, 인터페이스는, 그냥 좋은 형태입니다. 필요을하지 않습니다)

그리고 거기 당신은 기본 유형을 통해 그것에 대한 참조가있을지라도 요소가 자신의 유형 인에 고유 한 방문자 메서드 을 호출하는 이중 디스패치 방법을 사용합니다. 당신이 그것을 제대로 구현 한 경우, 화면에 "베타 오브젝트를 방문"을 참조한다

Alpha alpha = new Beta(); 
IVisitor visitor = new Visitor(); 
alpha.Accept(visitor); 

(또는, 당신의 측면에서, 당신이 원하는 "수신기"동작이 실행 볼 수 있습니다.)


고려할 수있는 또 다른 옵션은 기본 클래스에서 가상 메소드 Receiver을 만들고 해당 클래스에서 파생 클래스가 재정의하고 클래스 내에 비헤이비어가 클래스에 적합한 지 여부를 확인하는 것입니다. 비헤이비어가 외부에 있어야하는 경우 지정된 클래스에 대해 특정 프로세서를 만드는 방법을 알고있는 팩토리 방식을 고려할 수도 있습니다. 하위 유형이 기본을 기대하는 메소드로 전달되는 경우 프로그램 실행에 관련되지 않는 많은 옵션이 있습니다.


는 여기 조금 특별한 뭔가가 필요합니다. 모든 메소드에 알파 오브젝트를 전달할 수 있기를 원하지만 void와 같은 메소드를 원하지 않습니다. 수신자 (베타 베타); 베타에서 상속 유형의 객체 (즉

이 참으로 이상하다. 나는, 최악의 경우, 감마 또는 엡실론 객체가 전달됩니다 경우 예외를 제기 할 것이다. 그리고 내가받을 수있는 실제로 원하는 것을 확신 할 수 없습니다. 상속 계층 구조가 머리에 대칭 이동 된 것처럼 보입니다. 수퍼 유형은 파생 된 유형으로 대체 될 수 있고 반대로는 대체 될 수없는 것 같습니다. 정말로 당신이하려고하는 것을 다시 생각해보십시오. .

0

GetType을 수행하고 베타 버전을 확인할 수 있습니다.

+0

나는 그것을 파생시키고 싶다. 파생 된 타입인지는 확인하지 않는다. – bevacqua

+0

엡실론에서 새 베타 버전을 만드시겠습니까? –

+0

베타 버전에서 새'엡실론 '만들기 – bevacqua

0

나는 당신이 안정적으로 그렇게 할 수있는 모든 방법

에 알파 오브젝트를 통과 할 수 있어야합니다. Alpha는 감마가 아니므로이 매개 변수를 Receiver (감마)의 매개 변수로 사용할 수 없습니다. 그렇지 않으면 당신이 할 수 있습니다 : 당신은 당신이 당신의 질문에 그랬던 것처럼 수신기의 기능을 정의하는 경우 (당신이 그것을 던져 경우 또는 주조 형)

Alpha a = new Gamma(); // legal 
Receiver((Epsilon)a); // not legal 

는, 컴파일러가 선언 된 유형에 따라 적절한 방법을 선택합니다 :

Epsilon e = new Epsilon(); 
Alpha a = new Gamma(); 

Receiver(e);   // calls Receiver(Epsilon) 
Receiver(a);   // calls Receiver(Alpha) 
Receiver((Gamma)a); // calls Receiver(Gamma) 
Receiver((Beta)e); // calls Receiver(Beta) 

그래서 올바르게 호출하면 컴파일러가 적절한 방법을 선택합니다.

하지만 난 void Receiver(Beta beta); 같은 방법 그럼 당신은 제대로 상속을 사용하지 않는 베타

에서 상속 유형의 객체를 수신 할 수있는 싶지 않아요. GammaBeta입니다. 상속 된 형식이이 메서드를 사용하지 못하게하려는 이유는 무엇입니까? Gamma와 Beta가 상속없이 일부 속성/메서드를 공유하도록하려면 캡슐화 또는 컴포지션과 같은 다른 패턴을 선택하고 인터페이스를 사용하십시오.말했다

, 당신의 업 캐스팅 기능은 단순해야한다 :

public T Upcast<T>() where T : Alpha 
{ 
    return this as T; // will return null is this is not a T 
} 

... 

new Beta().Upcast<Gamma>(); // will return null 
new Epsilon().Upcate<Epsilon>(); // will return the Epsilon