2009-03-03 13 views
2

Heute, während der Implementierung einiger Testklassen in C#, stürzte ich auf einige Fragen in Bezug auf Vererbung (und Schnittstellen) in C#. Im Folgenden habe ich einen Beispielcode, um meine Fragen zu veranschaulichen.Unerwartete Verhalten von Vererbung und Schnittstellen in C#

interface ILuftfahrzeug 
{ 
    void Starten(); 
} 

class Flugzeug : ILuftfahrzeug 
{ 
    public void Starten() 
    { 
     Console.WriteLine("Das Flugzeug startet, "+Dings()); 
    } 

    protected string Dings() 
    { 
     return "Flugzeug Dings"; 
    } 
} 


class Motorflugzeug : Flugzeug, ILuftfahrzeug 
{ 
    public new void Starten() 
    { 
     Console.WriteLine("Das Motorflugzeug startet, "+Dings()); 
    } 

    protected new string Dings() 
    { 
     return "Motorflugzeug Dings"; 
    } 
} 

class InterfaceUndVererbung 
{ 
    static void Main(string[] args) 
    { 
     //Motorflugzeug flg = new Motorflugzeug(); // case1: returns "Das Motorflugzeug startet, Motorflugzeug Dings" 
     //Flugzeug flg = new Motorflugzeug(); // case2: returns "Das Flugzeug startet, Flugzeug Dings" 
     ILuftfahrzeug flg = new Motorflugzeug(); // case3: returns "Das Motorflugzeug startet, Motorflugzeug Dings" 
        // if Motorflugzeug implements ILuftfahrzeug explicitly, 
        // otherwise "Das Motorflugzeug startet, Motorflugzeug Dings" 

     flg.Starten(); 
     Console.ReadLine(); 
    } 
} 

Das sind meine Fragen:

  1. Deklarieren und Initialisieren mit Flugzeug flg = new Motorflugzeug(); (case2) Ich habe erwartet, dass Motorflugzeug.Starten statt Flugzeug.Starten aufgerufen wird (und ich bin mir ziemlich sicher, dass dies das Verhalten von Java ist). openbook.galileo sagt, dass in diesem Fall mit C# der Runtime-Typ Flugzeug ist. Gibt es einen Grund dafür? Ein solches Vererbungsverhalten macht für mich keinen Sinn.
  2. Gleiches mit ILuftfahrzeug flg = neues Motorflugzeug(); (case3) - hier könnte ich umgehen indem ich das Motorflugzeug explizit ILuftfahrzeug implementiere (wie es im Beispielcode ist). Aber für mich ist das überflüssig, da Flugzeug ILuftfahrzeug bereits implementiert.
  3. Jetzt möchte ich eine geschützte Methoden Dings(), die von Starten() aufgerufen wird überschreiben. Wenn ich den Code ausführe, wie es im Beispiel implementiert ist, funktioniert alles. Aber wenn Steigen() nicht in Motorflugzeug implementiert wird, wird Dings() der Basisklasse anstelle von Motorflugzeug.Dings() aufgerufen. Mir wurde gesagt, dass Java auch dieses Verhalten zeigt.
    Gibt es ein Muster, um dies zu umgehen? Sonst müsste ich jede Methode überschreiben (hier: Starten()), die die Methode aufruft, die ich eigentlich überschreiben möchte (hier: Dings()), auch wenn sie genau so ist wie in der Basisklasse.

Antwort

9

1: Sie sind Wieder erklärt das Verfahren (new); wenn du override es sollte funktionieren. Die new bricht jedes polymorphe Verhalten.

2: Sie sind Re-Implementieren die Schnittstelle; Dies nennt in der Tat die höchste Implementierung. Auch dies würde override beheben.

1

Stellen Sie sicher, dass Sie die Methode, die Sie überschreiben möchten, als virtuell deklarieren. Dann verwenden Sie das Schlüsselwort override für die geerbte Klasse.

Update 1: Das neue Schlüsselwort macht explizit die Tatsache, dass nur eine nicht-virtuelle Methode auf die geerbte Klasse deklarieren wird nur die Basis-Methode verbergen, wenn Sie direkt mit dieser Klasse arbeiten. Wann immer Sie mit der Basisklasse arbeiten, gibt es nichts zu verbergen.

0

Das neue Schlüsselwort und das Schlüsselwort override machen zwei sehr unterschiedliche Dinge, und Sie erleben das Verhalten von new, wo Sie von Ihrer Beschreibung aus Override verwenden möchten, da dies den normalerweise erwarteten Verhaltensweisen folgt. Sie müssen die Methode/Eigenschaft virtual in der Basisklasse deklarieren und stattdessen override statt new verwenden.

Doh, zu langsam!

0

Es ist, weil Sie die „neue“ Modifikator verwenden, finden Sie MSDN

Sie sollten „überschreiben“ verwenden, anstatt

0

implementierte Schnittstelle Mitglieder sind nicht automatisch virtuell. Es liegt an dir, sie virtuell, abstrakt usw. zu machen.

0

Der Grund, warum Ihr Programm nicht das tut, was Sie erwarten, ist wegen des Schlüsselwortes new in Ihrer Methode.

Die C# -Methode ist standardmäßig nicht dynamisch gebunden. Dies bedeutet, dass die aufgerufene Methode zur Kompilierzeit ermittelt wird. Sie können sich ansehen, wie der Typ der Variablen bestimmt, welche Methode anstelle des tatsächlichen Objekts dahinter im Speicher aufgerufen wird.

Um den gewünschten Effekt zu erzielen, müssen Sie sicherstellen, dass c3 die Methode dynamisch bindet. Sie können etwas tun, indem Sie die Methode virtual und die übergeordnete Methode override deklarieren.

class Flugzeug : ILuftfahrzeug 
{ 
    public virtual void Starten() 
    { 
     Console.WriteLine("Das Flugzeug startet, "+Dings()); 
    } 

    protected virtual string Dings() 
    { 
     return "Flugzeug Dings"; 
    } 
} 


class Motorflugzeug : Flugzeug, ILuftfahrzeug 
{ 
    public override void Starten() 
    { 
     Console.WriteLine("Das Motorflugzeug startet, "+Dings()); 
    } 

    protected override string Dings() 
    { 
     return "Motorflugzeug Dings"; 
    } 
} 

Verwenden Sie im Allgemeinen nie new für eine Methode. Es macht fast nie was du willst.

0

Ich zweite Freddy Rios Punkt über das virtuelle Schlüsselwort. Wenn Ihre Basisklasse keine Methode mit dem virtuellen Schlüsselwort deklariert, wird es überhaupt kein polymorphes Verhalten geben. Es spielt keine Rolle, ob Sie override oder new verwenden.

Verwandte Themen