Share via


Versionshantering med åsidosättning och nya nyckelord (C#-programmeringsguide)

C#-språket är utformat så att versionshantering mellan basklasser och härledda klasser i olika bibliotek kan utvecklas och upprätthålla bakåtkompatibilitet. Det innebär till exempel att introduktionen av en ny medlem i en basklass med samma namn som en medlem i en härledd klass stöds helt av C# och inte leder till oväntat beteende. Det innebär också att en klass uttryckligen måste ange om en metod är avsedd att åsidosätta en ärvd metod eller om en metod är en ny metod som döljer en ärvd metod med liknande namn.

I C#kan härledda klasser innehålla metoder med samma namn som basklassmetoder.

  • Om metoden i den härledda klassen inte föregås av nya nyckelord eller åsidosätter nyckelord utfärdar kompilatorn en varning och metoden fungerar som om nyckelordet new fanns.

  • Om metoden i den härledda klassen föregås av nyckelordet new definieras metoden som oberoende av metoden i basklassen.

  • Om metoden i den härledda klassen föregås av nyckelordet override anropar objekt i den härledda klassen den metoden i stället för basklassmetoden.

  • För att kunna tillämpa nyckelordet override på metoden i den härledda klassen måste basklassmetoden definieras virtuell.

  • Basklassmetoden kan anropas inifrån den härledda klassen med hjälp av nyckelordet base .

  • Nyckelorden override, virtualoch new kan också tillämpas på egenskaper, indexerare och händelser.

Som standard är C#-metoder inte virtuella. Om en metod deklareras som virtuell kan alla klasser som ärver metoden implementera sin egen version. För att göra en virtuell metod virtual används modifieraren i metoddeklarationen för basklassen. Den härledda klassen kan sedan åsidosätta den virtuella basmetoden med hjälp av nyckelordet override eller dölja den virtuella metoden i basklassen med hjälp av nyckelordet new . Om varken nyckelordet override eller nyckelordet new anges utfärdar kompilatorn en varning och metoden i den härledda klassen döljer metoden i basklassen.

För att demonstrera detta i praktiken antar du för ett ögonblick att företag A har skapat en klass med namnet GraphicsClass, som programmet använder. Följande är GraphicsClass:

class GraphicsClass
{
    public virtual void DrawLine() { }
    public virtual void DrawPoint() { }
}

Ditt företag använder den här klassen och du använder den för att härleda din egen klass och lägger till en ny metod:

class YourDerivedGraphicsClass : GraphicsClass
{
    public void DrawRectangle() { }
}

Ditt program används utan problem tills företag A släpper en ny version av GraphicsClass, som liknar följande kod:

class GraphicsClass
{
    public virtual void DrawLine() { }
    public virtual void DrawPoint() { }
    public virtual void DrawRectangle() { }
}

Den nya versionen av GraphicsClass nu innehåller en metod med namnet DrawRectangle. Till en början sker ingenting. Den nya versionen är fortfarande binär kompatibel med den gamla versionen. Alla program som du har distribuerat fortsätter att fungera, även om den nya klassen är installerad på dessa datorsystem. Alla befintliga anrop till metoden DrawRectangle fortsätter att referera till din version i din härledda klass.

Men så snart du kompilera om ditt program med den nya versionen av GraphicsClassfår du en varning från kompilatorn CS0108. Den här varningen informerar dig om att du måste tänka på hur du vill att din DrawRectangle metod ska bete sig i ditt program.

Om du vill att metoden ska åsidosätta den nya basklassmetoden använder du nyckelordet override :

class YourDerivedGraphicsClass : GraphicsClass
{
    public override void DrawRectangle() { }
}

Nyckelordet override ser till att alla objekt som härleds från YourDerivedGraphicsClass använder den härledda klassversionen av DrawRectangle. Objekt som härleds från YourDerivedGraphicsClass kan fortfarande komma åt basklassversionen av DrawRectangle med hjälp av basnyckelordet:

base.DrawRectangle();

Om du inte vill att metoden ska åsidosätta den nya basklassmetoden gäller följande överväganden. För att undvika förvirring mellan de två metoderna kan du byta namn på din metod. Detta kan vara tidskrävande och felbenäget, och bara inte praktiskt i vissa fall. Men om projektet är relativt litet kan du använda Alternativen för refaktorisering i Visual Studio för att byta namn på metoden. Mer information finns i Omstrukturera klasser och typer (klassdesigner).

Du kan också förhindra varningen med hjälp av nyckelordet new i din härledda klassdefinition:

class YourDerivedGraphicsClass : GraphicsClass
{
    public new void DrawRectangle() { }
}

Med hjälp av nyckelordet new anger kompilatorn att definitionen döljer definitionen som finns i basklassen. Det här är standardbeteendet.

Åsidosättning och metodval

När en metod namnges i en klass väljer C#-kompilatorn den bästa metoden att anropa om fler än en metod är kompatibel med anropet, till exempel när det finns två metoder med samma namn och parametrar som är kompatibla med parametern som skickas. Följande metoder skulle vara kompatibla:

public class Derived : Base
{
    public override void DoWork(int param) { }
    public void DoWork(double param) { }
}

När DoWork anropas på en instans av Derivedförsöker C#-kompilatorn först göra anropet kompatibelt med de versioner av DoWork som ursprungligen deklarerades den Derived. Åsidosättningsmetoder betraktas inte som deklarerade för en klass. De är nya implementeringar av en metod som deklarerats för en basklass. Endast om C#-kompilatorn inte kan matcha metodanropet till en ursprunglig metod på Derivedförsöker den matcha anropet till en åsidosatt metod med samma namn och kompatibla parametrar. Till exempel:

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

Eftersom variabeln val kan konverteras till en dubbel implicit anropar DoWork(double) C#-kompilatorn i stället DoWork(int)för . Det finns två sätt att undvika detta. Undvik först att deklarera nya metoder med samma namn som virtuella metoder. För det andra kan du instruera C#-kompilatorn att anropa den virtuella metoden genom att göra en sökning i basklassmetodlistan genom att omvandla instansen av Derived till Base. Eftersom metoden är virtuell anropas implementeringen av DoWork(int)Derived . Till exempel:

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

Fler exempel på new och finns i Veta när du ska använda åsidosättning och nya nyckelordoverride.

Se även