2010-02-09 3 views
5

그래, 다음을하려고합니다 :메소드 오버로드 : 파생 클래스 인수 오버로드에 대한 퍼널 호출

  protected bool ValidAdvert(Base item) 
     { 
      throw ThisIsAnAbstractClassException(); 
     } 

     protected bool ValidAdvert(Derived1 item) 
     { 
      return ADerived1SpecificPredicate; 
     } 

     protected bool ValidAdvert(Derived2 item) 
     { 
      return ADerived2SpecificPredicate; 
     }

그리고 메서드의 파생 클래스 버전을 호출 할 때, 기본 클래스가 메서드에 전달됩니다. 기본 클래스는 추상적이므로 이것이 이론적으로 가능해야합니까?

누군가가 클래스 자체에서 메소드를 오버로드하기 전에 클래스 내부의 논리는 많은 다른 조건에 의존하며 그 중 아무 것도 관련이 없으며 Base/Derived 클래스와 직접적으로 관련이 없습니다 (로그인 상태 등)

답변

6

이중 디스패치가 너무 방해가되는 경우 리플렉션을 통해 메서드를 호출하고 적절한 오버로드를 동적으로 해결할 수 있습니다.

protected bool ValidAdvert(Base item) 
{ 
    if (item.GetType() == typeof(Base)) 
     throw new ThisIsAnAbstractClassException(); 

    Type type = typeof(CurrentClass); 

    MethodInfo method = type.GetMethod("ValidAdvert", 
             BindingFlags.Instance | BindingFlags.NonPublic, 
             null, 
             new Type[] { item.GetType() }, 
             null); 
    return (bool)method.Invoke(this, new object[] { item }); 
} 

protected bool ValidAdvert(Derived1 item) 
{ 
    return ADerived1SpecificPredicate; 
} 

protected bool ValidAdvert(Derived2 item) 
{ 
    return ADerived2SpecificPredicate; 
} 

이 패턴을 반사하여 메소드를 호출하는 동안 (이 방법은 초당 수백 회 미만이라고 경우 오버하지 않을 것이다), 그것이 갖는 직접 메소드를 호출보다 느리지 MultipleDispatch라고 Double Dispatch 패턴과 같이 클래스 계층 구조를 수정할 필요가없는 이점.

# 4.0 c를 동적 키워드로 나오는 경우가 더 쉽게 될 것입니다 :

protected bool ValidAdvert(Base item) 
{ 
    if (item.GetType() == typeof(Base)) 
     throw new ThisIsAnAbstractClassException(); 

    dynamic dynamicThis = this; 

    return (bool)dynamicThis.ValidAdvert(item as dynamic); 
} 
+0

또한 똑똑하고 다양한 파생 클래스를 망칠 필요가 없습니다 (2 개만 있으면 좋겠다!). –

+0

꽤 노트 : 당신은 반환에 bool에 캐스팅해야하고 method.Invoke는 객체의 []를 취합니다. 그래서 당신이 시도하고 그냥 통과하면 :) craps Thanks! –

+0

@Ed - 파생 클래스로 조건부를 유지하는 것이 실제로 바람직한 방법이라고 생각합니다. 파생 클래스 별 논리를 기본 클래스에 저장하면이 두 클래스간에 역방향 연결이 생성됩니다. 나는 이것을 전혀 좋은 것으로 보지 않는다. 기본 클래스는 파생 클래스에 대해 알 필요가 없습니다. – tvanfosson

5

사용할 수있는 완벽한 장소로 double dispatch :

class Base 
{ 
    public abstract bool IsValid(IAdvertValidator validator); 
} 

class Derived1 : Base 
{ 
    public bool IsValid(IAdvertValidator validator) 
    { 
     return validator.ValidAdvert(this); 
    } 
} 

class Derived2 : Base 
{ 
    public bool IsValid(IAdvertValidator validator) 
    { 
     return validator.ValidAdvert(this); 
    } 
} 

interface IAdvertValidator 
{ 
    bool ValidAdvert(Derived1 d1); 
    bool ValidAdvert(Derived2 d2); 
} 
+0

영리한, 나는 그것을 좋아한다. –

+0

패턴의 적절한 사용. 대안은 유효성 검사기에서 유효성 검사 메서드를 노출하고 클래스의 실제 유효성 검사 흐름을 유지하면서 IsValid 구현 내에서 유효성 검사 메서드를 사용하는 것입니다. – tvanfosson

0

나는 당신이 이제까지 실제로 인스턴스가 아닌 기본 클래스의 인스턴스가 정확히 얼마나 확실하지 않다 파생 된 클래스의 기본 클래스는 추상 클래스이므로 인스턴스화 할 수 없습니다. 특정 서명이없는 파생 클래스와 일치한다고 가정합니다. 그러나 이는 사용자가 수행하는 것으로 보이지 않습니다.

+0

예, 항상 파생 클래스 중 하나입니다. 그러나 기술적으로는 기본 클래스이기도합니다. 예를 들어 기본 클래스 메서드가 호출 될 때 (List ) i.Where (ValidateAdvert)와 같이 호출됩니다. –

+0

아 - 질문을 읽지 않고 코드 샘플을 읽었습니다. 실제로 예외를 throw하지 않으려면 대신 다른 메서드 중 하나를 호출해야합니다. 이 경우에는 @ Anton의 제안이나 비슷한 것을 사용합니다. 인수로서 전달할 필요가 없도록 생성자에 유효성 검사기를 제공 할 수 있습니다. 또한 정적 속성의 유효성을 검사하는 정적 유효성 검사 클래스를 사용하여 참조를 유지해야하는 필요성을 제거했습니다. 하지만 조심하지 않으면 테스트가 더 어려워 질 수 있으므로주의해야합니다. – tvanfosson

+0

유효성 검사기는 대단히 페이지 및 상태 별 클래스이므로 정적으로 잘 작동하지 않지만 반사 방식에서는 상당히 잘 작동한다고 생각합니다. 기본적으로 지원되지 않습니다 그래도! –

관련 문제