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á overrideslova a , newvirtuallze 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 Derivedkompilá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 , Derivedpokusí 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 newoverride, viz Znalost kdy použít přepsání a nová klíčová slova.

Viz také