Nadpisania w VB.NET

Override są często mylone z Overloads i Shadows.

Getty Images/Jetta Productions zdjęcie kobiety korzystającej z komputera

Kobieta siedzi przed komputerem. Getty Images/Jetta Productions





Jest to jedna z mini-serii, która omawia różnice w przeciążeniach, cieniach i przeciążeniach w VB.NET . W tym artykule omówiono nadpisania. Artykuły, które obejmują pozostałe, znajdują się tutaj:

-> Przeciążenia
-> Cienie



Te techniki może być bardzo myląca; istnieje wiele kombinacji tych słów kluczowych i podstawowych opcji dziedziczenia. Własna dokumentacja Microsoftu nie oddaje sprawiedliwości w temacie, aw sieci jest wiele złych lub nieaktualnych informacji. Najlepszą radą, aby upewnić się, że program jest poprawnie zakodowany, jest „Testuj, testuj i testuj ponownie”. W tej serii przyjrzymy się im pojedynczo, kładąc nacisk na różnice.

Nadpisania

Wspólną cechą Shadows, Overloads i Overrides jest to, że ponownie używają nazw elementów, zmieniając to, co się dzieje. Shadows i Overloads mogą działać zarówno w ramach tej samej klasy, jak i gdyklasa dziedziczyinna klasa. Zastąpień jednak można używać tylko w klasie pochodnej (czasami nazywanej klasą podrzędną), która dziedziczy z klasy klasa podstawowa (czasami nazywana klasą nadrzędną). A Overrides to młot; pozwala całkowicie zastąpić metodę (lub właściwość) z klasy bazowej.



W artykule o klasach i słowie kluczowym Shadows (Patrz: Shadows in VB.NET) dodano funkcję pokazującą, że można odwoływać się do dziedziczonej procedury.

|_+_|

Kod, który tworzy wystąpienie klasy pochodnej od tego (CodedProfessionalContact w przykładzie), może wywołać tę metodę, ponieważ jest dziedziczona.

W przykładzie użyłem VB.NET PobierzHashCode metoda, aby kod był prosty, a to zwróciło dość bezużyteczny wynik, wartość -520086483. Załóżmy, że chcę zamiast tego zwrócić inny wynik, ale

-> Nie mogę zmienić klasy bazowej. (Może wszystko, co mam, to skompilowany kod od dostawcy.)



... oraz ...

-> Nie mogę zmienić kodu dzwoniącego (może jest tysiąc kopii i nie mogę ich zaktualizować.)



Jeśli mogę zaktualizować klasę pochodną, ​​mogę zmienić zwrócony wynik. (Na przykład kod może być częścią aktualizowalnej biblioteki DLL).

Jest jeden problem. Ponieważ jest tak wszechstronna i wszechstronna, musisz mieć uprawnienia klasy bazowej, aby używać Override. Ale zapewniają to dobrze zaprojektowane biblioteki kodu. ( Twój wszystkie biblioteki kodu są dobrze zaprojektowane, prawda?) Na przykład funkcja dostarczona przez Microsoft, której właśnie użyliśmy, jest możliwa do zastąpienia. Oto przykład składni.



Publiczna funkcja zastępowalna GetHashCode As Integer

Więc to słowo kluczowe musi być również obecne w naszej przykładowej klasie bazowej.



|_+_|

Zastępowanie metody jest teraz tak proste, jak podanie nowego słowa kluczowego Overrides. Program Visual Studio ponownie umożliwia rozpoczęcie pracy, wypełniając kod za pomocą Autouzupełniania. Kiedy wchodzisz ...

|_+_|

Visual Studio automatycznie dodaje resztę kodu, gdy tylko wpiszesz nawias otwierający, w tym instrukcję return, która wywołuje tylko oryginalną funkcję z klasy bazowej. (Jeśli po prostu coś dodajesz, jest to zwykle dobre rozwiązanie po wykonaniu nowego kodu).

|_+_|

W tym przypadku jednak zamierzam zastąpić tę metodę czymś równie bezużytecznym, aby zilustrować, jak to się robi: funkcję VB.NET, która odwróci ciąg.

|_+_|

Teraz kod wywołujący otrzymuje zupełnie inny wynik. (Porównaj z wynikiem w artykule o Shadows.)

|_+_|

Możesz też nadpisać właściwości. Załóżmy, że zdecydowałeś, że wartości ContactID większe niż 123 nie będą dozwolone i powinny mieć wartość domyślną 111. Możesz po prostu nadpisać właściwość i zmienić ją po zapisaniu właściwości:

|_+_|

Otrzymasz ten wynik, gdy zostanie przekazana większa wartość:

|_+_|

Nawiasem mówiąc, w przykładowym kodzie do tej pory wartości całkowite są podwojone w New podprogram (Zobacz artykuł o Cieniach), więc liczba całkowita 123 zostaje zmieniona na 246, a następnie ponownie zmieniona na 111.

VB.NET zapewnia jeszcze większą kontrolę, zezwalając klasie bazowej na wyraźne wymaganie lub odmowę zastąpienia klasy pochodnej przy użyciu słów kluczowych MustOverride i NotOverridable w klasie bazowej. Ale oba te są używane w dość specyficznych przypadkach. Po pierwsze, nie do zastąpienia.

Skoro wartością domyślną dla klasy publicznej jest NotOverridable, dlaczego miałbyś kiedykolwiek ją określać? Jeśli spróbujesz tego z funkcją HashTheName w klasie bazowej, otrzymasz błąd składni, ale tekst komunikatu o błędzie daje wskazówkę:

Nie można określić „NotOverridable” dla metod, które nie zastępują innej metody.

Wartość domyślna dla zastąpionej metody jest odwrotna: Overrideable. Więc jeśli chcesz, aby zastępowanie zdecydowanie się na tym skończyło, musisz określić NotOverridable w tej metodzie. W naszym przykładowym kodzie:

|_+_|

Wtedy jeśli klasa CodedProfessionalContact jest z kolei dziedziczona...

|_+_|

... funkcja HashTheName nie może być zastąpiona w tej klasie. Element, którego nie można nadpisać, jest czasami nazywany elementem zapieczętowanym.

Podstawowa część . Fundacja NET jest wymaganie, aby cel każdej klasy był wyraźnie zdefiniowany, aby usunąć wszelką niepewność. Problem w poprzednich językach OOP nazywano delikatną klasą bazową. Dzieje się tak, gdy klasa bazowa dodaje nową metodę o tej samej nazwie co nazwa metody w podklasie, która dziedziczy po klasie bazowej. Programista piszący podklasę nie planował nadpisania klasy bazowej, ale tak się dzieje. Wiadomo, że spowodowało to krzyk rannego programisty: „Nic nie zmieniłem, ale mój program i tak się zawiesił”. Jeśli istnieje możliwość, że klasa zostanie zaktualizowana w przyszłości i spowoduje to ten problem, zadeklaruj ją jako NotOverridable.

MustOverride jest najczęściej używany w tak zwanej klasie abstrakcyjnej. (W C# to samo używa słowa kluczowego Abstract!) Jest to klasa, która po prostu udostępnia szablon i oczekuje się, że wypełnisz go własnym kodem. Microsoft podaje następujący przykład:

|_+_|

Kontynuując przykład Microsoftu, pralki będą wykonywać te czynności (mycie, płukanie i wirowanie) zupełnie inaczej, więc nie ma żadnej korzyści z definiowania funkcji w klasie bazowej. Zaletą jest jednak upewnienie się, że każda klasa, która odziedziczy tę klasę czy zdefiniuj je. Rozwiązanie: klasa abstrakcyjna.

Jeśli potrzebujesz jeszcze więcej wyjaśnień na temat różnic między przeciążeniami a nadpisaniami, w krótkiej wskazówce przedstawiono zupełnie inny przykład: Przeciążenia kontra nadpisania

VB.NET zapewnia jeszcze większą kontrolę, zezwalając klasie bazowej na wyraźne wymaganie lub odmowę zastąpienia klasy pochodnej przy użyciu słów kluczowych MustOverride i NotOverridable w klasie bazowej. Ale oba te są używane w dość specyficznych przypadkach. Po pierwsze, nie do zastąpienia.

Skoro wartością domyślną dla klasy publicznej jest NotOverridable, dlaczego miałbyś kiedykolwiek ją określać? Jeśli spróbujesz tego z funkcją HashTheName w klasie bazowej, otrzymasz błąd składni, ale tekst komunikatu o błędzie daje wskazówkę:

Nie można określić „NotOverridable” dla metod, które nie zastępują innej metody.

Wartość domyślna dla zastąpionej metody jest dokładnie odwrotna: Overrideable. Więc jeśli chcesz, aby zastępowanie zdecydowanie się na tym skończyło, musisz określić NotOverridable w tej metodzie. W naszym przykładowym kodzie:

|_+_|

Wtedy jeśli klasa CodedProfessionalContact jest z kolei dziedziczona...

|_+_|

... funkcja HashTheName nie może być zastąpiona w tej klasie. Element, którego nie można nadpisać, jest czasami nazywany elementem zapieczętowanym.

Podstawową częścią .NET Foundation jest wymaganie, aby cel każdej klasy został wyraźnie zdefiniowany, aby usunąć wszelką niepewność. Problem w poprzednich językach OOP nazywano delikatną klasą bazową. Dzieje się tak, gdy klasa bazowa dodaje nową metodę o tej samej nazwie co nazwa metody w podklasie, która dziedziczy po klasie bazowej. Programista piszący podklasę nie planował nadpisania klasy bazowej, ale tak się dzieje. Wiadomo, że spowodowało to krzyk rannego programisty: „Nic nie zmieniłem, ale mój program i tak się zawiesił”. Jeśli istnieje możliwość, że klasa zostanie w przyszłości zaktualizowana i spowoduje ten problem, zadeklaruj ją jako NotOverridable.

MustOverride jest najczęściej używany w tak zwanej klasie abstrakcyjnej. (W C# to samo używa słowa kluczowego Abstract!) Jest to klasa, która po prostu udostępnia szablon i oczekuje się, że wypełnisz go własnym kodem. Microsoft podaje następujący przykład:

|_+_|

Kontynuując przykład Microsoftu, pralki będą wykonywać te czynności (mycie, płukanie i wirowanie) zupełnie inaczej, więc nie ma żadnej korzyści z definiowania funkcji w klasie bazowej. Zaletą jest jednak upewnienie się, że każda klasa, która odziedziczy tę klasę czy zdefiniuj je. Rozwiązanie: klasa abstrakcyjna.

Jeśli potrzebujesz jeszcze więcej wyjaśnień na temat różnic między przeciążeniami a nadpisaniami, w krótkiej wskazówce przedstawiono zupełnie inny przykład: Przeciążenia kontra nadpisania