Správa verzí pomocí klíčových slov override a new (Průvodce programováním v C#)
Jazyk C# je navržený tak, aby se správa verzí mezi základní a odvozenou sadou v různých knihovnách vyvinula a zachovala zpětnou kompatibilitu. To například znamená, že zavedení nového člena do základní třídy se stejným názvem jako člen v odvozené třídě je plně podporováno jazykem C# a nemá za následek neočekávané chování. Také to znamená, že třída musí explicitně uvést, zda je metoda určena k přepsání zděděné metody, nebo zda metoda je nová metoda, která skryje podobně pojmenovanou zděděnou metodu.
V jazyce C# mohou odvozené třídy obsahovat metody se stejným názvem jako metody základní třídy.
Pokud metoda v odvozené třídě není před novými klíčovými slovy nebo přepsána , kompilátor vydá upozornění a metoda se bude chovat, jako kdyby
new
bylo klíčové slovo přítomno.Pokud je metoda v odvozené třídě před klíčovým slovem
new
, metoda je definována jako nezávislá na metodě v základní třídě.Pokud je metoda v odvozené třídě před klíčovým slovem
override
, objekty odvozené třídy budou volat tuto metodu namísto metody základní třídy.Aby bylo možné použít
override
klíčové slovo na metodu v odvozené třídě, musí být metoda základní třídy definována virtuální.Metodu základní třídy lze volat z odvozené třídy pomocí klíčového
base
slova.Klíčová
override
slova a ,new
virtual
lze použít také pro vlastnosti, indexery a události.
Ve výchozím nastavení nejsou metody jazyka C# virtuální. Pokud je metoda deklarována jako virtuální, může každá třída dědící metodu implementovat vlastní verzi. Chcete-li vytvořit metodu virtuální, virtual
modifikátor se používá v deklaraci metody základní třídy. Odvozená třída pak může přepsat základní virtuální metodu pomocí klíčového override
slova nebo skrýt virtuální metodu v základní třídě pomocí klíčového new
slova. Pokud není override
zadáno klíčové slovo ani new
klíčové slovo, kompilátor vydá upozornění a metoda v odvozené třídě skryje metodu v základní třídě.
Abychom to ukázali v praxi, předpokládejme, že společnost A vytvořila třídu s názvem GraphicsClass
, kterou program používá. Následuje:GraphicsClass
class GraphicsClass
{
public virtual void DrawLine() { }
public virtual void DrawPoint() { }
}
Vaše společnost používá tuto třídu a používá ji k odvození vlastní třídy a přidává novou metodu:
class YourDerivedGraphicsClass : GraphicsClass
{
public void DrawRectangle() { }
}
Vaše aplikace se používá bez problémů, dokud společnost A uvolní novou verzi GraphicsClass
, která se podobá následujícímu kódu:
class GraphicsClass
{
public virtual void DrawLine() { }
public virtual void DrawPoint() { }
public virtual void DrawRectangle() { }
}
Nová verze GraphicsClass
nyní obsahuje metodu s názvem DrawRectangle
. Zpočátku se nic nestává. Nová verze je stále binární kompatibilní se starou verzí. Veškerý software, který jste nasadili, bude fungovat i v případě, že je v těchto počítačových systémech nainstalována nová třída. Všechna existující volání metody DrawRectangle
budou nadále odkazovat na vaši verzi v odvozené třídě.
Jakmile však aplikaci znovu zkompilujete pomocí nové verze GraphicsClass
, obdržíte upozornění z kompilátoru CS0108. Toto upozornění vás informuje, že musíte zvážit, jak se má vaše DrawRectangle
metoda chovat ve vaší aplikaci.
Pokud chcete, aby vaše metoda přepsala novou metodu override
základní třídy, použijte klíčové slovo:
class YourDerivedGraphicsClass : GraphicsClass
{
public override void DrawRectangle() { }
}
Klíčové override
slovo zajišťuje, že všechny objekty odvozené z YourDerivedGraphicsClass
budou používat odvozenou třídu verze DrawRectangle
. Objekty odvozené z YourDerivedGraphicsClass
můžou dál přistupovat k verzi DrawRectangle
základní třídy pomocí základního klíčového slova:
base.DrawRectangle();
Pokud nechcete, aby vaše metoda přepsala novou metodu základní třídy, platí následující aspekty. Abyste se vyhnuli nejasnostem mezi těmito dvěma metodami, můžete metodu přejmenovat. To může být časově náročné a náchylné k chybám a v některých případech to není praktické. Pokud je ale projekt relativně malý, můžete metodu přejmenovat pomocí možností refaktoringu sady Visual Studio. Další informace najdete v tématu Refaktoring tříd a typů (Návrhář tříd).
Případně můžete zabránit upozornění použitím klíčového slova new
v definici odvozené třídy:
class YourDerivedGraphicsClass : GraphicsClass
{
public new void DrawRectangle() { }
}
Použití klíčového new
slova říká kompilátoru, že definice skryje definici obsaženou v základní třídě. Toto je výchozí chování.
Přepsání a výběr metody
Pokud je metoda pojmenována ve třídě, kompilátor jazyka C# vybere nejlepší metodu volání, pokud je více než jedna metoda kompatibilní s voláním, například pokud existují dvě metody se stejným názvem a parametry, které jsou kompatibilní s předaným parametrem. Následující metody by byly kompatibilní:
public class Derived : Base
{
public override void DoWork(int param) { }
public void DoWork(double param) { }
}
Při DoWork
volání instance Derived
kompilátoru jazyka C# se nejprve pokusí provést volání kompatibilní s verzemi DoWork
deklarovaných původně v Derived
. Metody přepsání nejsou považovány za deklarované ve třídě, jedná se o nové implementace metody deklarované v základní třídě. Pouze pokud kompilátor jazyka C# nemůže odpovídat volání metody původní metodě na , Derived
pokusí se spárovat volání přepsané metody se stejným názvem a kompatibilními parametry. Příklad:
int val = 5;
Derived d = new Derived();
d.DoWork(val); // Calls DoWork(double).
Vzhledem k tomu, že proměnnou val
lze převést na dvojitou implicitně, volání DoWork(double)
kompilátoru jazyka C# namísto DoWork(int)
. Existují dva způsoby, jak se tomu vyhnout. Nejprve se vyhněte deklarování nových metod se stejným názvem jako virtuální metody. Za druhé, můžete dát kompilátoru jazyka C# pokyn, aby volal virtuální metodu tím, že prohledá seznam metod základní třídy přetypováním instance Derived
na Base
. Vzhledem k tomu, že metoda je virtuální, bude volána implementace on DoWork(int)
Derived
. Příklad:
((Base)d).DoWork(val); // Calls DoWork(int) on Derived.
Další příklady a new
override
, viz Znalost kdy použít přepsání a nová klíčová slova.