Przechowywanie wersji przesłonięć i nowych słów kluczowych (Przewodnik programowania w języku C#)
Język C# został zaprojektowany tak, aby przechowywanie wersji między klasami podstawowymi i pochodnymi w różnych bibliotekach może ewoluować i zachować zgodność z poprzednimi wersjami. Oznacza to na przykład, że wprowadzenie nowego elementu członkowskiego w klasie bazowej o takiej samej nazwie jak składowa w klasie pochodnej jest całkowicie obsługiwane przez język C# i nie prowadzi do nieoczekiwanego zachowania. Oznacza to również, że klasa musi jawnie określić, czy metoda ma zastąpić dziedziczonej metody, czy też metoda jest nową metodą, która ukrywa metodę o podobnej nazwie dziedziczonej.
W języku C#klasy pochodne mogą zawierać metody o tej samej nazwie co metody klasy bazowej.
Jeśli metoda w klasie pochodnej nie jest poprzedzona nowymi lub zastępowanymi słowami kluczowymi, kompilator wyda ostrzeżenie, a metoda będzie zachowywać się tak, jakby
new
słowo kluczowe było obecne.Jeśli metoda w klasie pochodnej jest poprzedzona
new
słowem kluczowym, metoda jest definiowana jako niezależna od metody w klasie bazowej.Jeśli metoda w klasie pochodnej jest poprzedzona
override
słowem kluczowym, obiekty klasy pochodnej wywołają tę metodę zamiast metody bazowej.Aby zastosować
override
słowo kluczowe do metody w klasie pochodnej, należy zdefiniować metodę klasy bazowej.Metodę klasy bazowej można wywołać z klasy pochodnej przy użyciu słowa kluczowego
base
.Słowa
override
kluczowe ,virtual
inew
można również stosować do właściwości, indeksatorów i zdarzeń.
Domyślnie metody języka C# nie są wirtualne. Jeśli metoda jest zadeklarowana jako wirtualna, każda klasa dziedzicząca metodę może zaimplementować własną wersję. Aby utworzyć metodę wirtualną, virtual
modyfikator jest używany w deklaracji metody klasy bazowej. Klasa pochodna może następnie zastąpić podstawową metodę wirtualną za pomocą override
słowa kluczowego lub ukryć metodę wirtualną w klasie bazowej przy użyciu słowa kluczowego new
. Jeśli ani override
słowo kluczowe, ani słowo kluczowe nie new
zostanie określone, kompilator wyświetli ostrzeżenie, a metoda w klasie pochodnej ukryje metodę w klasie bazowej.
Aby to zademonstrować w praktyce, załóżmy na chwilę, że firma A utworzyła klasę o nazwie GraphicsClass
, której używa program. Poniżej przedstawiono następujące elementy:GraphicsClass
class GraphicsClass
{
public virtual void DrawLine() { }
public virtual void DrawPoint() { }
}
Firma używa tej klasy i używa jej do utworzenia własnej klasy, dodając nową metodę:
class YourDerivedGraphicsClass : GraphicsClass
{
public void DrawRectangle() { }
}
Aplikacja jest używana bez problemów, dopóki firma A nie wyda nowej wersji GraphicsClass
programu , która przypomina następujący kod:
class GraphicsClass
{
public virtual void DrawLine() { }
public virtual void DrawPoint() { }
public virtual void DrawRectangle() { }
}
Nowa wersja programu GraphicsClass
zawiera teraz metodę o nazwie DrawRectangle
. Początkowo nic się nie dzieje. Nowa wersja jest nadal binarna zgodna ze starą wersją. Wszelkie wdrożone oprogramowanie będzie nadal działać, nawet jeśli nowa klasa jest zainstalowana w tych systemach komputerowych. Wszystkie istniejące wywołania metody DrawRectangle
będą nadal odwoływać się do używanej wersji w klasie pochodnej.
Jednak po ponownym skompilowaniu aplikacji przy użyciu nowej wersji GraphicsClass
programu zostanie wyświetlone ostrzeżenie kompilatora CS0108. To ostrzeżenie informuje, że musisz wziąć pod uwagę sposób DrawRectangle
zachowania metody w aplikacji.
Jeśli chcesz, aby metoda przesłoniła nową metodę klasy bazowej, użyj słowa kluczowego override
:
class YourDerivedGraphicsClass : GraphicsClass
{
public override void DrawRectangle() { }
}
Słowo override
kluczowe zapewnia, że wszystkie obiekty pochodzące z YourDerivedGraphicsClass
klasy będą używać pochodnej DrawRectangle
wersji klasy . Obiekty pochodzące z YourDerivedGraphicsClass
programu mogą nadal uzyskiwać dostęp do wersji DrawRectangle
klasy bazowej przy użyciu podstawowego słowa kluczowego:
base.DrawRectangle();
Jeśli nie chcesz, aby metoda przesłoniła nową metodę klasy bazowej, należy wziąć pod uwagę następujące zagadnienia. Aby uniknąć nieporozumień między dwiema metodami, możesz zmienić nazwę metody. Może to być czasochłonne i podatne na błędy, a po prostu nie jest praktyczne w niektórych przypadkach. Jeśli jednak projekt jest stosunkowo mały, możesz użyć opcji refaktoryzacji programu Visual Studio, aby zmienić nazwę metody. Aby uzyskać więcej informacji, zobacz Refaktoryzacja klas i typów (klasa Projektant).
Alternatywnie możesz zapobiec ostrzeżeniu, używając słowa kluczowego new
w definicji klasy pochodnej:
class YourDerivedGraphicsClass : GraphicsClass
{
public new void DrawRectangle() { }
}
Użycie słowa kluczowego new
informuje kompilator, że definicja ukrywa definicję zawartą w klasie bazowej. To jest zachowanie domyślne.
Zastępowanie i wybór metody
Gdy metoda ma nazwę w klasie, kompilator języka C# wybiera najlepszą metodę do wywołania, jeśli więcej niż jedna metoda jest zgodna z wywołaniem, na przykład gdy istnieją dwie metody o tej samej nazwie i parametry zgodne z przekazanym parametrem. Następujące metody byłyby zgodne:
public class Derived : Base
{
public override void DoWork(int param) { }
public void DoWork(double param) { }
}
Po DoWork
wywołaniu w wystąpieniu Derived
programu kompilator języka C# najpierw spróbuje wykonać wywołanie zgodne z wersjami zadeklarowanymi DoWork
pierwotnie na .Derived
Metody przesłonięcia nie są uznawane za zadeklarowane w klasie. Są to nowe implementacje metody zadeklarowanej w klasie bazowej. Tylko wtedy, gdy kompilator języka C# nie może dopasować wywołania metody do oryginalnej metody w systemie Derived
, spróbuje dopasować wywołanie metody do metody przesłoniętej o tej samej nazwie i zgodnych parametrach. Na przykład:
int val = 5;
Derived d = new Derived();
d.DoWork(val); // Calls DoWork(double).
Ponieważ zmienną val
można przekonwertować na dwukrotnie niejawnie, kompilator języka C# wywołuje DoWork(double)
zamiast DoWork(int)
. Istnieją dwa sposoby, aby tego uniknąć. Najpierw należy unikać deklarowania nowych metod o tej samej nazwie co metody wirtualne. Po drugie, można poinstruować kompilator języka C#, aby wywołał metodę wirtualną, wyszukując listę metod klasy bazowej przez rzutowanie wystąpienia Derived
do Base
klasy . Ponieważ metoda jest wirtualna, zostanie wywołana implementacja DoWork(int)
polecenia on Derived
. Na przykład:
((Base)d).DoWork(val); // Calls DoWork(int) on Derived.
Aby uzyskać więcej przykładów elementów new
i , zobacz Wiedza o tym, kiedy używać przesłonięć i nowych słów kluczowychoverride
.