Sdílet prostřednictvím


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 metodě v odvozené třídě nepředcházejí klíčová slova new nebo override, kompilátor vydá upozornění a metoda se bude chovat, jako by bylo klíčové slovo new přítomné.

  • 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á slova override, virtual a new lze také použít 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í klíčové slovo override ani klíčové slovo new zadáno, 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 tuto třídu používá ke svým účelům, zatímco vy ji využíváte k odvození vlastní třídy a přidání nové metody.

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 v základní třídě, použijte klíčové slovo override.

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 volání DoWork na instanci Derived se kompilátor jazyka C# nejprve pokusí provést volání tak, aby bylo kompatibilní s verzemi DoWork původně deklarovanými na Derived. Metody přepsání se neberou jako deklarované v rámci třídy; jedná se o nové implementace metod deklarovaných v základní třídě. Pouze pokud kompilátor jazyka C# nedokáže sladit volání metody s původní metodou na Derived, pokusí se sladit toto volání s přepsanou metodou se stejným názvem a kompatibilními parametry. Například:

int val = 5;
Derived d = new();
d.DoWork(val);  // Calls DoWork(double).

Vzhledem k tomu, že proměnnou val lze implicitně převést na typ double, kompilátor jazyka C# volá DoWork(double) 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 na DoWork(int) a Derived. Například:

((Base)d).DoWork(val);  // Calls DoWork(int) on Derived.

Pro další příklady new a override, viz Kdy použít přetížení a nová klíčová slova.

Viz také