it-swarm.com.de

# - Virtuelle Keyword-Verwendung + Überschreiben vs. Neues

Was ist der Unterschied zwischen der Deklaration einer Methode in einem Basistyp "virtual" und der anschließenden Überschreibung in einem untergeordneten Typ mit dem Schlüsselwort "override" im Gegensatz zur einfachen Verwendung des Schlüsselworts "new" bei der Deklaration der übereinstimmenden Methode im untergeordneten Typ? 

193
i3ensays

Das Schlüsselwort "new" wird nicht überschrieben, sondern bezeichnet eine neue Methode, die nichts mit der Basisklassenmethode zu tun hat. 

public class Foo
{
     public bool DoSomething() { return false; }
}

public class Bar : Foo
{
     public new bool DoSomething() { return true; }
}

public class Test
{
    public static void Main ()
    {
        Foo test = new Bar ();
        Console.WriteLine (test.DoSomething ());
    }
}

Dies gibt den Wert false aus. Wenn Sie die Überschreibung verwendet haben, wurde der Wert true ausgegeben.

(Basiscode von Joseph Daigle übernommen)

Wenn Sie also echten Polymorphismus betreiben, sollten Sie IMMER ÜBERHOLEN . Der einzige Ort, an dem Sie "new" verwenden müssen, ist, wenn die Methode in keiner Weise mit der Basisklassenversion zusammenhängt.

174
albertein

Ich finde solche Dinge mit Bildern immer besser verständlich:

Wieder unter Joseph Daigles Code,

public class Foo
{
     public /*virtual*/ bool DoSomething() { return false; }
}

public class Bar : Foo
{
     public /*override or new*/ bool DoSomething() { return true; }
}

Wenn Sie den Code dann so aufrufen:

Foo a = new Bar();
a.DoSomething();

HINWEIS: Wichtig ist, dass unser Objekt tatsächlich eine Bar ist, aber wir speichern es in einer Variablen vom Typ Foo (dies ähnelt dem Casting)

Das Ergebnis sieht dann wie folgt aus, abhängig davon, ob Sie bei der Deklaration Ihrer Klassen virtual/override oder new verwendet haben.

 Virtual/Override explanation image

218
Orion Edwards

Hier ist etwas Code, um den Unterschied im Verhalten von virtuellen und nicht virtuellen Methoden zu verstehen:

class A
{
    public void foo()
    {
        Console.WriteLine("A::foo()");
    }
    public virtual void bar()
    {
        Console.WriteLine("A::bar()");
    }
}

class B : A
{
    public new void foo()
    {
        Console.WriteLine("B::foo()");
    }
    public override void bar()
    {
        Console.WriteLine("B::bar()");
    }
}

class Program
{
    static int Main(string[] args)
    {
        B b = new B();
        A a = b;
        a.foo(); // Prints A::foo
        b.foo(); // Prints B::foo
        a.bar(); // Prints B::bar
        b.bar(); // Prints B::bar
        return 0;
    }
}
41
Franci Penov

Das new-Schlüsselwort erstellt tatsächlich ein komplett neues Element, das nur für diesen bestimmten Typ vorhanden ist.

Zum Beispiel

public class Foo
{
     public bool DoSomething() { return false; }
}

public class Bar : Foo
{
     public new bool DoSomething() { return true; }
}

Die Methode existiert bei beiden Typen. Wenn Sie Reflection verwenden und die Member vom Typ Bar erhalten, werden Sie tatsächlich zwei Methoden mit dem Namen DoSomething() finden, die genau gleich aussehen. Wenn Sie new verwenden, verbergen Sie die Implementierung effektiv in der Basisklasse, sodass der Methodenaufruf von base.DoSomething() auf Bar und nicht auf Bar geht, wenn Klassen von Foo abgeleitet werden.

19
Joseph Daigle

virtual/override teilt dem Compiler mit, dass die beiden Methoden verwandt sind und dass es unter bestimmten Umständen korrekt ist, wenn Sie die erste (virtuelle) Methode aufrufen, die zweite (überschriebene) Methode aufzurufen. Dies ist die Grundlage des Polymorphismus.

(new SubClass() as BaseClass).VirtualFoo()

Ruft die überschriebene VirtualFoo () - Methode der SubClass auf.

new teilt dem Compiler mit, dass Sie einer abgeleiteten Klasse eine Methode hinzufügen, die denselben Namen wie eine Methode in der Basisklasse hat, jedoch keine Beziehung zueinander besteht.

(new SubClass() as BaseClass).NewBar()

Ruft die NewBar () - Methode der BaseClass auf, wobei:

(new SubClass()).NewBar()

Ruft die NewBar () - Methode der SubClass auf.

9
Wedge

Über die technischen Details hinaus glaube ich, dass die Verwendung von Virtual/Override eine Menge semantischer Informationen über das Design vermittelt. Wenn Sie eine Methode als virtuell deklarieren, geben Sie an, dass Sie erwarten, dass implementierende Klassen ihre eigenen, nicht standardmäßigen Implementierungen bereitstellen möchten. Das Auslassen in einer Basisklasse erklärt ebenfalls die Erwartung, dass die Standardmethode für alle implementierenden Klassen ausreichen sollte. In ähnlicher Weise können abstrakte Deklarationen verwendet werden, um die Implementierung von Klassen zu erzwingen, um ihre eigene Implementierung bereitzustellen. Ich denke, dass dies wiederum viel darüber spricht, wie der Programmierer den Code erwartet. Wenn ich sowohl die Basis- als auch die Implementierungsklasse schreibe und mich mit new beschäftigen würde, würde ich die Entscheidung ernsthaft überdenken, die Methode nicht virtuell im übergeordneten Element zu machen und meine Absicht ausdrücklich zu erklären.

8
tvanfosson

Der Unterschied zwischen dem Überschreibungsschlüsselwort und dem neuen Schlüsselwort besteht darin, dass die erste Methode die Methode überschreibt und die spätere Methode sie versteckt.

Weitere Informationen finden Sie in den folgenden Links ...

MSDN und Sonstiges

4
Nescio
  • Das new-Schlüsselwort dient zum Ausblenden. - bedeutet, dass Sie Ihre Methode zur Laufzeit ausblenden. Die Ausgabe basiert auf der Basisklassenmethode.
  • override zum Überschreiben. - bedeutet, dass Sie Ihre abgeleitete Klassenmethode mit der Referenz der Basisklasse aufrufen. Die Ausgabe basiert auf einer abgeleiteten Klassenmethode.
3
Chetan

Meine Erklärungsversion kommt von der Verwendung von properties , um die Unterschiede zu verstehen.

override ist einfach genug, oder? Der zugrunde liegende Typ überschreibt der übergeordneten.

new ist vielleicht irreführend (für mich war das so). Mit Eigenschaften ist es einfacher zu verstehen:

public class Foo
{
    public bool GetSomething => false;
}

public class Bar : Foo
{
    public new bool GetSomething => true;
}

public static void Main(string[] args)
{
    Foo foo = new Bar();
    Console.WriteLine(foo.GetSomething);

    Bar bar = new Bar();
    Console.WriteLine(bar.GetSomething);
}

Wenn Sie einen Debugger verwenden, können Sie feststellen, dass Foo foo 2 GetSomething -Eigenschaften hat, da es tatsächlich zwei Versionen der Eigenschaft hat, Foo_s und Bar_s. 

Wenn Sie die Version der Leiste verwenden wollten, hätten Sie stattdessen die Überschreibung oder Foo foo verwendet.

Bar bar hat nur 1 , wie es vollständig neues Verhalten für GetSomething will.

1
Dror Weiss

Eine Methode nicht mit etwas markieren, bedeutet: Binden Sie diese Methode mit dem Compile-Typ des Objekts, nicht mit dem Laufzeit-Typ (statische Bindung). 

Das Markieren einer Methode mit virtual bedeutet: Binden Sie diese Methode mit dem Laufzeittyp des Objekts, nicht mit dem Zeittyp für die Kompilierung (dynamisches Binden). 

Das Markieren einer Basisklasse virtual-Methode mit override in abgeleiteter Klasse bedeutet: Dies ist die Methode, die mit dem Laufzeittyp des Objekts (dynamische Bindung) verbunden werden soll. 

Das Markieren einer Basisklasse virtual-Methode mit new in abgeleiteter Klasse bedeutet: Dies ist eine neue Methode, die keinen Bezug zu der gleichnamigen Klasse in der Basisklasse hat und mit dem Compile-Time-Typ des Objekts (statische Bindung) gebunden werden sollte. 

Eine Basisklasse virtual-Methode in der abgeleiteten Klasse nicht markieren, bedeutet: Diese Methode wird als new (statische Bindung) markiert. 

Eine Methode markieren abstract bedeutet: Diese Methode ist virtuell, aber ich werde keinen Körper für sie deklarieren, und ihre Klasse ist auch abstrakt (dynamische Bindung). 

0
Emre Tapcı