2013-01-25 10 views
50

Angenommen, wenn ich eine Schnittstelle haben, wie unten definiert:C# Interface-Vererbung zu Abstrakte Klasse

public interface IFunctionality 
{ 
    void Method();  
} 

und ich diese Schnittstelle für eine abstrakte Klasse implementieren, wie unten dargestellt:

public abstract class AbstractFunctionality: IFunctionality 
{ 
    public void Method() 
    { 
     Console.WriteLine("Abstract stuff" + "\n"); 
    }  
} 

habe ich wieder ein konkrete Klasse, die aus der abstrakten Klasse wie folgt übernommen:

public class ConcreteFunctionality: AbstractFunctionality 
{ 
    public void Method() 
    { 
     Console.WriteLine("Concrete stuff" + "\n"); 
    } 
} 

Jetzt habe ich die folgenden co de,

Die Ausgabe, die ich nach der Ausführung dieses Zeug bekomme, ist wie folgt

Concrete stuff 
Abstract stuff 
Abstract stuff 

Aber was ich habe den Ausgang erwartet zu werden „Concrete Stuff“ in allen drei Fällen als das, was ich hier mache die Referenz von ConcreteFunctionality auf die Variablen des Typs AbstractFunctionality und IFunctionality zuweist.

Was geschieht intern? Bitte klären Sie.

+2

Dies könnte etwas aufheben: http://stackoverflow.com/questions/392721/difference-between-shadowing-and-overriding-in-c- – Stormenet

+0

"Es ist versteckt, nicht überschrieben" - ein gutes Mantra zu erinnern. (Aber Ihr Compiler sollte dies erwähnt haben; haben Sie Ihre Warnungen herausgefiltert?) – kmote

Antwort

74

hier:

public class ConreteFunctionality:AbstractFunctionality 
{ 
    public void Method() 
    { 
     Console.WriteLine("Concrete stuff" + "\n"); 
    } 
} 

... Sie nicht die bestehenden Methode überschrieben. Sie erstellen eine neue Methode, die die bestehende versteckt. (Sie sollten auch eine Warnung erhalten, die die Verwendung des Modifikators new vorschlägt, wenn Sie dieses Verhalten wirklich möchten.) Die Schnittstelle wurde in AbstractFunctionality implementiert, sodass sich die Schnittstellenzuordnungstabelle auf die Methode in dieser Klasse bezieht.

Nun, wenn Sie die Schnittstelle reimplementieren :

public class ConcreteFunctionality : AbstractFunctionality, IFunctionality 

... dann das Interface-Mapping auf das Verfahren in ConcreteFunctionality beziehen, und Sie werden das Verhalten Sie erwarten für den Anruf durch die Schnittstelle erhalten (d. HIhr dritter Anruf), aber Sie würden immer noch die Implementierung in AbstractFunctionality für Ihren zweiten Anruf erhalten.

Es wäre in der Regel sauberer und gesünder, die Methode in AbstractFunctionality virtuell zu machen und sie in ConcreteFunctionality zu überschreiben. Auf diese Weise wird in allen Fällen die Implementierung ConcreteFunctionality verwendet.

+1

Das würde das Verhalten nicht erwarten, da der zweite Aufruf immer noch durch die abstrakte Implementierung erfolgen würde. –

+0

@JonHanna: Ich hatte die Erwartung nicht bemerkt, dass der zweite Aufruf * auch * die konkrete Version verwenden würde. Wird bearbeiten. –

14

Sie vermissen virtual und override Schlüsselwörter. Ohne dies erhalten Sie keine virtuellen Funktionen.

Sie können Method in AbstractFunctionality als virtual markieren und die Method in ConreteFunctionality als override markieren. Wie mihirj gezeigt hat.

ähnliche Probleme in Angriff genommen in - Why are C# interface methods not declared abstract or virtual?

+1

+1 für den interessanten Link. – phoog

30

Sie müssen als Klassen definiert:

public abstract class AbstractFunctionality:IFunctionality 
{ 
    public virtual void Method() 
    { 
     Console.WriteLine("Abstract stuff" + "\n"); 
    }  
} 

public class ConreteFunctionality:AbstractFunctionality 
{ 
    public override void Method() 
    { 
     Console.WriteLine("Concrete stuff" + "\n"); 
    } 
} 

Wie Sie nicht außer Kraft gesetzt Methode haben() in ConreteFunctionality, die Laufzeitumgebung führt Methode() im Zusammenhang mit AbstractFunctionality Objekt, da es hier keinen dynamischen Polymorphismus anwenden kann. Mit der Einführung von virtual und override wird die Laufzeitumgebung zur Ausführung der überschriebenen Methode in der untergeordneten Klasse festgelegt.

+2

Schöne Antwort; aber ich würde den Begriff "Verstecken" einführen, der den ursprünglichen Code des OP beschreibt, und beachten, dass das Verstecken einer Methode ohne das Schlüsselwort "new" zu einer Compiler-Warnung führt. – phoog