// Cannot change source code
class Base
{
public virtual void Say()
{
Console.WriteLine("Called from Base.");
}
}
// Cannot change source code
class Derived : Base
{
public override void Say()
{
Console.WriteLine("Called from Derived.");
base.Say();
}
}
class SpecialDerived : Derived
{
public override void Say()
{
Console.WriteLine("Called from Special Derived.");
base.Say();
}
}
class Program
{
static void Main(string[] args)
{
SpecialDerived sd = new SpecialDerived();
sd.Say();
}
}
Wynik to:
Nazywany Special Derived.
Nazywany od Derived. / * to nie jest oczekiwane * /
Zadzwoniono z bazy.
Jak mogę przepisać klasę SpecialDerived, aby metoda klasy średniej „Derived” nie była wywoływana?
AKTUALIZACJA:
Powodem, dla którego chcę dziedziczyć po Derived zamiast Base jest klasa pochodna, która zawiera wiele innych implementacji. Ponieważ nie mogę tego zrobić base.base.method()
, myślę, że najlepszym sposobem jest wykonanie następujących czynności?
// Nie można zmienić kodu źródłowego
class Derived : Base
{
public override void Say()
{
CustomSay();
base.Say();
}
protected virtual void CustomSay()
{
Console.WriteLine("Called from Derived.");
}
}
class SpecialDerived : Derived
{
/*
public override void Say()
{
Console.WriteLine("Called from Special Derived.");
base.Say();
}
*/
protected override void CustomSay()
{
Console.WriteLine("Called from Special Derived.");
}
}
c#
polymorphism
AZ.
źródło
źródło
Odpowiedzi:
Chcę tylko to dodać, ponieważ ludzie nadal wracają do tego pytania nawet po wielu latach. Oczywiście jest to zła praktyka, ale nadal można (w zasadzie) zrobić to, czego chce autor:
źródło
Func<stuff>
zamiastAction
Jest to zła praktyka programistyczna i niedozwolona w C #. To zła praktyka programistyczna, ponieważ
Szczegóły dotyczące głównej bazy są szczegółami implementacji bazy; nie powinieneś na nich polegać. Klasa bazowa dostarcza abstrakcji ponad grandbase; powinieneś używać tej abstrakcji, a nie budować obejścia, aby tego uniknąć.
Aby zilustrować konkretny przykład z poprzedniego punktu: jeśli jest to dozwolone, ten wzorzec byłby kolejnym sposobem uczynienia kodu podatnym na awarie klas bazowych. Załóżmy, że
C
pochodzi z, zB
którego pochodziA
. KodC
używanybase.base
do wywołania metodyA
. Wtedy autorB
zdaje sobie sprawę, że włożyli zbyt wiele narzędzi do klasyB
i lepszym podejściem jest stworzenie klasy pośredniej,B2
która pochodziA
iB
pochodzi zB2
. Po tej zmianie kod wC
wywołuje metodę wB2
, a nie wA
, ponieważC
autor przyjął założenie, że szczegóły implementacjiB
, a mianowicie, że jego bezpośrednią klasą bazową jestA
, nigdy się nie zmieni. Wiele decyzji projektowych w C # ma na celu złagodzenie prawdopodobieństwa różnego rodzaju kruchych awarii bazy; decyzja o uznaniu ich zabase.base
nielegalną całkowicie zapobiega temu szczególnemu posmakowi tego wzorca niepowodzenia.Wywodzisz się ze swojej bazy, ponieważ lubisz to, co robi i chcesz ją ponownie wykorzystać i rozszerzyć. Jeśli nie podoba ci się to, co robi i chcesz to obejść zamiast pracować z tym, to dlaczego w ogóle z tego wyprowadziłeś? Czerp sam z siebie, jeśli jest to funkcja, którą chcesz wykorzystać i rozszerzyć.
Baza może wymagać pewnych niezmienników dla celów bezpieczeństwa lub spójności semantycznej, które są utrzymywane przez szczegóły dotyczące sposobu, w jaki baza używa metod grandbase. Zezwolenie klasie pochodnej bazy na pominięcie kodu, który utrzymuje te niezmienniki, może wprowadzić bazę w niespójny, uszkodzony stan.
źródło
Nie możesz z C #. W IL jest to faktycznie obsługiwane. Możesz zadzwonić non-virt do którejkolwiek ze swoich klas rodzicielskich ... ale nie rób tego. :)
źródło
Odpowiedź (o której wiem, że nie jest tym, czego szukasz) brzmi:
Prawda jest taka, że masz bezpośrednią interakcję tylko z klasą, z której dziedziczysz. Pomyśl o tej klasie jak o warstwie - dostarczającej tyle lub tak mało jej lub funkcji rodzica, ile sobie tego życzy, do klas pochodnych.
EDYTOWAĆ:
Twoja edycja działa, ale myślę, że użyłbym czegoś takiego:
Oczywiście w prawdziwej implementacji możesz zrobić coś podobnego dla rozszerzalności i łatwości konserwacji:
Następnie klasy pochodne mogą odpowiednio kontrolować stan swoich rodziców.
źródło
Derived
której wywołaniaBase.Say
, aby można ją było wywołaćSpecialDerived
? Prostsze, nie?Dlaczego po prostu nie rzucić klasy potomnej na określoną klasę nadrzędną i nie wywołać wtedy konkretnej implementacji? Jest to sytuacja szczególna i należy zastosować rozwiązanie dla przypadku specjalnego. Będziesz jednak musiał użyć
new
słowa kluczowego w metodach dzieci.źródło
źródło
Możesz również utworzyć prostą funkcję w klasie pochodnej pierwszego poziomu, aby wywołać funkcję grand base
źródło
Moim 2c w tym celu jest zaimplementowanie funkcjonalności, której potrzebujesz, aby zostać wywołanym w klasie zestawu narzędzi i wywołać ją z dowolnego miejsca:
Wymaga to przemyślenia, aby uzyskać uprawnienia dostępu, może być konieczne dodanie niektórych
internal
metod dostępu, aby ułatwić funkcjonalność.źródło
W przypadkach, w których nie masz dostępu do źródła klasy pochodnej, ale potrzebujesz całego źródła klasy pochodnej oprócz bieżącej metody, zalecałbym również wykonanie klasy pochodnej i wywołanie implementacji klasy pochodnej.
Oto przykład:
źródło
Jak widać z poprzednich postów, można argumentować, że jeśli trzeba obejść funkcjonalność klas, to coś jest nie tak w architekturze klas. To może być prawda, ale nie zawsze można zrestrukturyzować lub zmienić strukturę klas w dużym, dojrzałym projekcie. Różne poziomy zarządzania zmianami mogą stanowić jeden problem, ale utrzymanie istniejącej funkcjonalności działającej tak samo po refaktoryzacji nie zawsze jest zadaniem trywialnym, zwłaszcza jeśli obowiązują ograniczenia czasowe. W dojrzałym projekcie powstrzymanie różnych testów regresji przed przejściem po restrukturyzacji kodu może być dużym przedsięwzięciem; często pojawiają się niejasne „dziwactwa”. Mieliśmy podobny problem w niektórych przypadkach dziedziczona funkcjonalność nie powinna być wykonywana (lub powinna wykonywać coś innego). Podejście, które zastosowaliśmy poniżej, polegało na umieszczeniu kodu podstawowego, który należy wykluczyć, w oddzielnej funkcji wirtualnej. Tę funkcję można następnie przesłonić w klasie pochodnej, a funkcjonalność wykluczyć lub zmienić. W tym przykładzie można zapobiec wyświetlaniu „Tekstu 2” w klasie pochodnej.
źródło
Wydaje się, że istnieje wiele pytań dotyczących dziedziczenia metody składowej z klasy dziadków, przesłaniania jej w drugiej klasie, a następnie ponownego wywoływania jej metody z klasy wnuków. Dlaczego po prostu nie odziedziczyć członków dziadków aż do wnuków?
Wydaje się proste ... wnuk dziedziczy tutaj metodę dziadków. Pomyśl o tym… w ten sposób „Object” i jego składowe, takie jak ToString (), są dziedziczone do wszystkich klas w C #. Myślę, że Microsoft nie wykonał dobrej roboty w wyjaśnianiu podstawowego dziedziczenia. Zbyt duży nacisk kładzie się na polimorfizm i implementację. Kiedy przeglądam ich dokumentację, nie ma przykładów na tę bardzo podstawową ideę. :(
źródło
Jeśli chcesz uzyskać dostęp do danych klasy bazowej, musisz użyć słowa kluczowego „this” lub użyć tego słowa kluczowego jako odniesienia dla klasy.
źródło