Unterschied zwischen Abschatten und Überschreiben in C #?


100

Was ist der Unterschied zwischen dem Abschatten und Überschreiben einer Methode in C #?

Antworten:


152

Gut Vererbung ...

Angenommen, Sie haben diese Klassen:

class A {
   public int Foo(){ return 5;}
   public virtual int Bar(){return 5;}
}
class B : A{
   public new int Foo() { return 1;}     //shadow
   public override int Bar() {return 1;} //override
}

dann, wenn Sie dies nennen:

A clA = new A();
B clB = new B();

Console.WriteLine(clA.Foo()); // output 5
Console.WriteLine(clA.Bar()); // output 5
Console.WriteLine(clB.Foo()); // output 1
Console.WriteLine(clB.Bar()); // output 1

//now let's cast B to an A class
Console.WriteLine(((A)clB).Foo()); // output 5 <<<-- shadow
Console.WriteLine(((A)clB).Bar()); // output 1

Angenommen, Sie haben eine Basisklasse und verwenden die Basisklasse in Ihrem gesamten Code anstelle der geerbten Klassen. Wenn Sie Shadow verwenden, werden die von der Basisklasse zurückgegebenen Werte zurückgegeben, anstatt dem Vererbungsbaum des realen Objekttyps zu folgen.

Führen Sie hier Code aus

Hoffe ich mache Sinn :)


16
Das Überschreiben bietet Polymorphismus, das Abschatten bietet eine andere Implementierung auf dieser Hierarchieebene, jedoch nicht polymorph.
David Rodríguez - Dribeas

@dribeas, Welche Definition von Polymorphismus würden Sie verwenden, um diese Schlussfolgerung zu ziehen?
AnthonyWJones

9
@AnthonyWJones, Polymorphismus ist die Fähigkeit eines (abgeleiteten) Typs, als anderer (Basis-) Typ verwendet zu werden, wobei die tatsächliche Implementierung (Verhalten) die des realen spezifischen (abgeleiteten) Typs ist. Wenn Sie überschreiben, wird die abgeleitete Methode durch Bezugnahme auf die Basis aufgerufen, aber wenn Sie Schatten, der nicht wahr ist
David Rodríguez - dribeas

2
Mir scheint, Sie haben einen Fehler in Ihrem Beispielcode. Das Casting sollte ((A) clB) sein .Foo (), nicht wahr?
Trend

1
Nein, da die Bar virtuell ist, wird sie weiterhin die B-Bar
Stormenet

32

Shadowing ist eigentlich eine VB-Sprache für das, was wir als Verstecken in C # bezeichnen würden.

Oft werden Verstecken (Abschatten in VB) und Überschreiben wie in der Antwort von Stormenet angezeigt .

Es wird gezeigt, dass eine virtuelle Methode von einer Unterklasse überschrieben wird. Wenn diese Methode auch für den Superklassentyp oder aus dem Code der Superklasse aufgerufen wird, wird die Ersatzimplementierung von der Unterklasse aufgerufen.

Anschließend wird eine konkrete Methode angezeigt (eine, die nicht als virtuell oder abstrakt markiert ist), die mithilfe des newSchlüsselworts ausgeblendet wird, wenn eine Methode mit identischer Signatur für die Unterklasse definiert wird. In diesem Fall ist die neue Implementierung nur für die Unterklasse verfügbar, wenn die Methode für den Superklassentyp aufgerufen wird, für den die ursprüngliche Implementierung verwendet wird.

Was jedoch häufig übersehen wird, ist, dass es auch möglich ist, eine virtuelle Methode auszublenden.

class A
{
    public virtual void DoStuff() { // original implementation }
}

class B : A
{
    public new void DoStuff() {  //new implementation }
}

B b = new B();
A a = b;

b.DoStuff(); //calls new implementation
a.DoStuff(); //calls original implementation.

Beachten Sie im obigen Beispiel, dass DoStuff konkret wird und nicht überschrieben werden kann. Allerdings ist es auch möglich , sowohl die zu verwenden virtualund newKeywords zusammen.

class A
{
    public virtual void DoStuff() { // original implementation }
}

class B : A
{
    public new virtual void DoStuff() {  //new implementation }
}

class C : B
{
    public override void DoStuff() { //replacement implementation }
}

C c = new C();
B b = c;
A a = b;

c.DoStuff(); //calls replacement implementation
b.DoStuff(); //calls replacement implementation
a.DoStuff(); //calls original implementation.

Beachten Sie, dass trotz aller virtuellen Methoden die Überschreibung auf C die virtuelle Methode auf A nicht beeinflusst, da die Verwendung von newin B die A-Implementierung verbirgt.

Bearbeiten: In den Kommentaren zu dieser Antwort wurde darauf hingewiesen, dass das oben Genannte gefährlich oder zumindest nicht besonders nützlich sein kann. Ich würde ja sagen, es kann gefährlich sein und wäre da draußen, wenn es überhaupt nützlich wäre.

Insbesondere könnten Sie in alle möglichen Schwierigkeiten geraten, wenn Sie auch die Eingabehilfen ändern. Beispielsweise:-

public class Foo
{
    internal Foo() { }
    protected virtual string Thing() { return "foo"; }
}

public class Bar : Foo
{
 internal new string Thing() { return "bar"; }
}

Um einen externen Erbin Bar, Fooist die Umsetzung von Thing () bleibt zugänglich und überschreibbar. Alle rechtlichen und nach .NET-Regeln erklärbaren Regeln sind dennoch nicht ganz intuitiv.

Ich habe diese Antwort veröffentlicht, um das Verständnis dafür zu vertiefen, wie Dinge funktionieren, und nicht als Vorschlag für Techniken, die frei verwendet werden können.


2
Gut zu wissen. Obwohl seine Verwendung gefährlich sein kann :)
Stormenet

2
Alle Werkzeuge können gefährlich sein, wenn sie nicht ordnungsgemäß verwendet werden.
AnthonyWJones

1
Aber die Benutzerfreundlichkeit scheint wirklich fraglich! Gibt es eine "ernsthafte" Open-Source-App, die dies verwendet?
Jox

4
Benutzerfreundlichkeit? Meinst du Nützlichkeit? Dinge, die am Rande stehen, scheinen nutzlos zu sein, bis Sie sie brauchen.
AnthonyWJones

Es scheint, dass Shadowing NUR bei virtuellen und neuen Spielen ins Bild kommt. @ Stormenet's erklärt nur das Überschreiben, da es normal ist, dass eine Klasse ihre eigene Methode aufruft, es sei denn, sie ist virtuell.
Sumit Kapadia

6

Ich denke, der Hauptunterschied besteht darin, dass Sie beim Abschatten den Namen im Wesentlichen wiederverwenden und die Verwendung der Oberklasse einfach ignorieren. Mit dem Überschreiben ändern Sie die Implementierung, nicht jedoch die Zugänglichkeit und Signatur (z. B. Parametertypen und Rückgabe). Siehe http://www.geekinterview.com/question_details/19331 .


5

Shadowing ist ein VB.NET-Konzept. In C # wird Shadowing als Verstecken bezeichnet. Es verbirgt die abgeleitete Klassenmethode. Dies erfolgt mit dem Schlüsselwort 'new'.

Das Schlüsselwort Override wird verwendet, um eine völlig neue Implementierung einer Basisklassenmethode (mit 'Virtual' gekennzeichnet) in der abgeleiteten Klasse bereitzustellen.


Was meinen Sie. Die abgeleitete Klassenmethode wird ausgeblendet, stattdessen wird die Basisklassenmethode verwendet. ?
Shaijut

0

Grundsätzlich, wenn Sie etwas wie unten haben,

Class A
{
}

Class B:A
{
}

A a = new B();

Jede Methode, die Sie für das Objekt 'a' aufrufen, wird für den Typ 'a' ausgeführt (hier ist der Typ 'A'). Wenn Sie jedoch dieselbe Methode in Klasse B implementieren, die bereits in Klasse A vorhanden ist, wird der Compiler dies tun Geben Sie eine Warnung zur Verwendung eines Schlüsselworts "Neu" aus. Wenn Sie "Neu" verwenden, verschwindet die Warnung. Davon abgesehen gibt es keinen Unterschied zwischen der Verwendung von "Neu" oder der Nichtverwendung in der geerbten Klasse.

In einigen Situationen müssen Sie möglicherweise eine Methode der Referenzklasse aufrufen, die die jeweilige Instanz in diesem Moment enthält, anstatt eine Methode für den Objekttyp aufzurufen. Im obigen Fall ist die Referenz 'B', aber der Typ ist 'A'. Wenn Sie also möchten, dass der Methodenaufruf für 'B' ausgeführt wird, verwenden Sie Virtual und überschreiben, um dies zu erreichen.

Hoffe das hilft...

Daniel Sandeep.


0

Wenn es einen Fall gibt, in dem Sie den Inhalt einer Klasse nicht ändern können, sagen wir A, aber Sie möchten einige Methoden verwenden, zusammen mit einer Methode, deren Name üblich ist, können Sie Ihre eigene Methodenimplementierung durch die verwendennew Schlüsselwort verwenden.

Der springende Punkt ist, dass sowohl die Referenz als auch das Objekt vom gleichen Typ sein müssen.

class A
{
    public void Test()
    {
        Console.WriteLine("base");
    }
}

class B : A
{
    public new void Test()
    {
        Console.WriteLine("sub");
    }

    public static void Main(string[] args)
    {
        A a = new A();
        B aa = new B();
        a.Test();
        aa.Test();
    }
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.