2016-03-23 8 views
0

Ich bin überrascht, dass die Ausgabe der folgenden Konsole-Anwendung in C# zu sehen:Warum nennt foreach nicht die neue Methode der Kindklasse?

abstract class Shape 
{ 
    public abstract void Draw(); 
} 
class Circle : Shape 
{ 
    public override void Draw() 
    { 
     Console.WriteLine("Drawing Circle"); 
    } 
} 
class SpecialCircle : Circle 
{ 
    public new void Draw() 
    { 
     Console.WriteLine("Drawing SpecialCircle"); 
    } 
} 
class Program 
{ 
    static void Main(string[] args) 
    { 
     Shape[] myShapes = { new Circle(), new SpecialCircle() }; 
     foreach(Shape s in myShapes) 
     { 
      Console.WriteLine(s.GetType()); 
      s.Draw(); 
     } 
     SpecialCircle scirc = new SpecialCircle(); 
     scirc.Draw(); 
    } 
} 

, die den Ausgang hat:

CallChildClassMethod.Circle 
Drawing Circle 
CallChildClassMethod.SpecialCircle 
Drawing Circle 
Drawing SpecialCircle 
Press any key to continue . . . 

So frage ich mich, warum in der foreach-Anweisung erkennt, dass die zweite Element des Arrays ist ein SpecialCircle, verwendet jedoch die Methode Draw aus der Klasse Circle. Im Gegensatz zum Verhalten beim Definieren eines SpecialCircle Objekts außerhalb eines Arrays und einer foreach-Schleife.

Kann mir jemand helfen, das herauszufinden?

Antwort

4

Das ist, weil Sie das Schlüsselwort new verwenden, wenn Sie es in override ändern, erhalten Sie das Verhalten, das Sie erwarten.

new überschreibt nicht die Implementierung in der Basisklasse, es verbirgt es. Dies bedeutet im Wesentlichen, dass die Basisimplementierung aufgerufen wird, wenn die Instanz als Basis behandelt wird, und wenn sie als abgeleiteter Typ behandelt wird, wird die abgeleitete Implementierung aufgerufen.

Sie können dies testen, indem

SpecialCircle scirc = new SpecialCircle(); 
scirc.Draw(); 
Circle circle = scirc; 
circle.Draw(); 

tun Dies würde Ausgabe

Drawing SpecialCircle 
Drawing Circle 
+0

Dank! Wann würde ich dann neu sein wollen? – String

+1

Wenn Sie möchten, dass alles, was die Instanz als den Typ der abgeleiteten Klasse behandelt, diese Methode aufruft, aber Sie möchten, dass andere Klassen sie als Basis behandeln, um die Basisimplementierung aufzurufen. –

+0

Ich denke, die pragmatische Antwort ist "selten". Zugegeben, ich habe noch keine jahrzehntelange Erfahrung, aber in den Jahren der Erfahrung, die ich bis jetzt habe, hatte ich niemals jemals etwas für die "neue" Schlüsselwort-Fähigkeit, Mitglieder zu verstecken. – kai

0

Wenn Sie new verwenden, müssen Sie es über einen Verweis auf die Klasse SpecialCircle aufrufen. Wenn Sie außerhalb der Schleife anrufen, haben Sie einen Verweis auf SpecialCircle, wodurch die Methode new aufgerufen wird.