Pytania z rozmów vol. 2 – .NET – słowo new vs słowo override

Poprzedni wpis dotyczył cyklu życia strony w ASP.NET. Był związany z pytaniem, które trafiło mi się na jednej z rozmów kwalifikacyjnych. Po ukończeniu tamtego posta, zaczęły mi się przypominać również inne pytania. Stwierdziłem, że przez następne kilka tygodni będę tutaj na blogu zadawał jedno z takich pytań i starał się je rozwiązać, rozwiewając wszelkie wątpliwości.

Pytanie brzmiało: jaka jest różnica pomiędzy słowem new, a słowem override?

Zaczynając od przykładu:

class Program
    {
        static void Main(string[] args)
        {
            Parent p = new Parent();
            Child c = new Child();
            Parent pc = new Child();

            p.SayHelloWithOverride();
            p.SayHelloWithNew();
            // Hello I am parent!
            // Hello I am parent!

            c.SayHelloWithOverride();
            c.SayHelloWithNew();
            // Hello I am child!
            // Hello I am child!

            pc.SayHelloWithOverride();
            pc.SayHelloWithNew();
            // Hello I am child!
            // Hello I am parent! // ups, czy na pewno tego chcieliśmy?

        }
 }

 class Parent
 {
 public virtual void SayHelloWithOverride()
 {
 Console.WriteLine("Hello I am parent!");
 }

 public void SayHelloWithNew()
 {
 Console.WriteLine("Hello I am parent");
 }
 }

 class Child : Parent
 {
 public override void SayHelloWithOverride()
 {
 Console.WriteLine("Hello I am child!");
 }

 public new void SayHelloWithNew()
 {
 Console.WriteLine("Hello I am child!");
 }
 }

W momencie, gdy użyjemy słowa new w klasie dziedziczącej po bazowej, tak naprawdę tracimy polimorfizm. Metoda oznaczona w ten sposób nie będzie miała żadnego związku z metodą w klasie bazowej.

Można to porównać do ojca i syna. Syn dziedziczy od taty np. cechy charakteru, wzrost, różnego rodzaju tendencje. Załóżmy jednak, że ojciec – będący w tym przykładzie klasą bazową posiada posiada metodę ThrowStuff, która umożliwia mu wyrzucanie różnych rzeczy, np. ubrań czy śmieci. Natomiast jego syn – będący klasą pochodną posiada metodę ThrowStuff, która pozwala mu na rzucanie różnymi rzeczami, np. rzutkami, oszczepem itp. Pomiędzy tymi dwoma metodami nie ma żadnego związku, dotyczą zupełnie różnych aktywności.

Jeżeli użyjemy kombinacji dwóch słów – virtual w klasie bazowej i override w klasie pochodnej przy definiowaniu metody – polimorfizm zostanie zachowany, a klasa pochodna przesłoni klasę bazową. Metoda oznaczona w ten sposób ma związek z metodą w klasie bazowej, ale może się inaczej zachowywać.

Wracając do przykładu ojca i syna. Ojciec posiada metodę virtual void SayHello(), za pomocą której mówi – „Cześć, jestem rodzicem”, natomiast syn posiada metodę override void SayHello(), za pomocą której mówi – „Cześć, jestem dzieckiem”. Jak widać, funkcjonalność przedstawionej metody dotyczy tego samego obszaru.

Kolejnym dobrym przykładem jest człowiek oraz dziedziczący po nim szef kuchni. Otóż człowiek może „chrzanić” i będziemy przez to rozumieć, że gada głupoty. Dziedziczący po nim szef kuchni może „chrzanić” w inny sposób, co oznaczać będzie, że doprawia w jakiś sposób danie. W takim przypadku warto zastanowić się nad słowem kluczowym new.

5 uwag do wpisu “Pytania z rozmów vol. 2 – .NET – słowo new vs słowo override

  1. Mam wrażenie, że do Twojego przykładu wdał się błąd. Napisałeś „ups, czy na pewno tego chcieliśmy?” Odpowiedź brzmi tak tego chcieliśmy ponieważ metoda SayHelloWithNew nie jest wirtualna. W tym przypadku użycie new nie powoduje utracenia polimorfizmu ponieważ i tak go tutaj nie było. Jeśli usuniesz new to wynik wypisany na konsolę będzie taki sam. Użycie new w Twoim przykładzie powoduje natomiast inną rzecz tj. brak warning’a w czasie kompilacji.

  2. Cześć. Przejrzałem kod i to, co mi się rzuciło w oczy to pewna zła praktyka, która nie powinna mieć miejsca, czyli zaszywanie API w klasach bazowych. Te metody, zamiast mieć w sobie Console.Writeline(), powinny zwracać stringi (różne, w zależności od użytego słówka), natomiast to już aplikacja konsolowa (lub jakaś inna) powinna się zatroszczyć o to, w jaki sposób wyświetlić te dane użytkownikowi (Console.Writeline()).

    Pozdrawiam
    Piotr R.

    1. Piotrek, to jest tylko materiał poglądowy. Jeżeli jestes na WROC#, to Matt Ellis właśnie popełnił ten sam grzech w kilku swoich przykładach 😉 ale oczywiście pełna zgoda!

Zostaw komentarz

Wprowadź swoje dane lub kliknij jedną z tych ikon, aby się zalogować:

Logo WordPress.com

Komentujesz korzystając z konta WordPress.com. Wyloguj /  Zmień )

Zdjęcie na Google+

Komentujesz korzystając z konta Google+. Wyloguj /  Zmień )

Zdjęcie z Twittera

Komentujesz korzystając z konta Twitter. Wyloguj /  Zmień )

Zdjęcie na Facebooku

Komentujesz korzystając z konta Facebook. Wyloguj /  Zmień )

w

Connecting to %s