2013-05-04 17 views
5

Szukałem i nie byłem w stanie znaleźć żadnego rozwiązania mojego problemu. Mój scenariusz jest bardzo prosta:base.Method() z wieloma poziomami dziedziczenia, które nie są wywoływane?

public class A 
{ 
    public virtual void MethodOne() 
    { 
     Console.log("A"); 
    } 
} 

public class B : A 
{ 
    public override void MethodOne() 
    { 
     base.MethodOne(); 
     Console.log("B"); 
    } 
} 

public class C : B 
{ 
    public override void MethodOne() 
    { 
     base.MethodOne(); 
     Console.log("C"); 
    } 
} 

Co staram się zrobić, to mieć instancję klasy C (my name it „instanceC”) nazywamy zarówno zastąpiona metoda jego rodzica, a jego dziadkowie. Tak bym tego spodziewać:

instanceC.MethodOne(); 
// Output: 
// "A" 
// "B" 
// "C" 

Ale zamiast otrzymuję to:

instanceC.MethodOne(); 
// Output 
// "A" 
// "C" 

z metody klasy B. są pomijane. Czy to nie jest możliwe? Myślałem, że to jest cały punkt dziedziczenia/polimorfizmu. Z góry dziękuję!

+6

Czy jesteś pewien, że C pochodzi od B, a nie od A? – jure

+0

Dlaczego C Ovveride z B? chcesz, aby odziedziczył po A. – Derek

+10

Twój przykład działa zgodnie z oczekiwaniami i drukuje "ABC" – Lee

Odpowiedz

10

Twój przykład działa zgodnie z oczekiwaniami. Widzę A B C. Myślę, że twoim najprawdopodobniejszym problemem jest to, że C nie przedłuża B. Jednakże, pozwól mi zasugerować pewnie bezpieczniejszy wzór, gdy jesteśmy w tej sprawie. Wydaje się, że chcesz, aby wszystkie przesłonięcia metody MethodOne wykonywały kod z ich klas bazowych. Wspaniale, dziedziczenie jest dobrym wzorem do tego. Jednak w przypadku tego wzorca nie można wymuszać na inwerterach wykonywania logiki podstawowej, ponieważ nie można wymusić na nich wywołania base.MethodOne(). Nawet jeśli zadzwonią pod numer base.MethodOne(), nie można zagwarantować kolejności logiki. Czy wywołają one base.MethodOne() na początku metody, środka metody lub na końcu metody? Często w tego typu wzorach chcesz, aby podklasy wykonywały całą logikę podstawową na początku funkcji. Następujący wzór wymusza dziedziczenie do wykonywania logiki podstawowej w klasach bazowych zamówień. Jest technicznie mniej elastyczny, ale bezpieczniejszy, ponieważ dziedziczenie musi rozszerzać klasy bazowe w sposób określony przez klasy bazowe.

public class A 
{ 
    //Don't make this method virtual because you don't actually want inheritors 
    //to be able to override this functionality. Instead, you want inheritors 
    //to be able to append to this functionality. 
    public void MethodOne() 
    { 
     Console.WriteLine("A"); 
     MethodToBeOverriddenOne(); 
    } 
    //Expose a place where inheritors can add extra functionality 
    protected virtual void MethodToBeOverriddenOne() { }  
} 

public class B : A 
{ 
    //Seal the method because you don't actually want inheritors 
    //to be able to override this functionality. Instead, you want inheritors 
    //to be able to append to this functionality. 
    protected sealed override void MethodToBeOverriddenOne() 
    { 
     Console.WriteLine("B"); 
     MethodToBeOverriddenTwo(); 
    } 
    //Expose a place where inheritors can add extra functionality 
    protected virtual void MethodToBeOverriddenTwo() { } 
} 

public class C : B 
{ 
    protected sealed override void MethodToBeOverriddenTwo() 
    { 
     Console.WriteLine("C"); 
    } 
} 
+1

To jest lepsza odpowiedź niż inne, ponieważ wyraźnie pokazuje, jak zapewnić, by podstawowe metody były zawsze wywoływane. Nie mam pojęcia, dlaczego został wycofany. – Andy

+0

Mam mało snu, a wy mieliście rację; C nierozsądnie przedłużało A zamiast C. Tak więc, chociaż to był rzeczywiście problem, uważam, że jest to lepsze rozwiązanie i mam dobre wyniki. Dziękuję Ci! – helios

+0

To nie ja spadałem, myślałem, że to też jest lepsze niż moje i dałem temu +1 –

1

Zamieszczony przykład działa perfekcyjnie, cokolwiek robisz w swoim rzeczywistym kodzie, jest inne niż to, co napisałeś.

Here is your code running on ideone działa dokładnie tak, jak chciałeś.

using System; 

public class Test 
{ 
     public static void Main() 
     { 
       var c = new C(); 
       c.MethodOne(); 
     } 
} 

public class A 
{ 
    public virtual void MethodOne() 
    { 
     Console.WriteLine("A"); 
    } 
} 

public class B : A 
{ 
    public override void MethodOne() 
    { 
     base.MethodOne(); 
     Console.WriteLine("B"); 
    } 
} 

public class C : B 
{ 
    public override void MethodOne() 
    { 
     base.MethodOne(); 
     Console.WriteLine("C"); 
    } 
}