2013-08-08 10 views
22

Ich habe hier eine Schnittstelle namens IFish. Ich will es mit einer abstrakten Klasse abzuleiten (WalkingFishCommon), die eine unvollständige Umsetzung bereitstellt, so dass abgeleitete Klassen von WalkingFishCommon nicht die CanWalk Eigenschaft implementieren müssen:Wie erfülle ich den Compiler, wenn ich nur teilweise eine Schnittstelle mit einer abstrakten Klasse implementiere?

interface IFish 
{ 
    bool Swim(); 
    bool CanWalk { get; } 
} 

abstract class WalkingFishCommon : IFish 
{ 
    bool IFish.CanWalk { get { return true; } } 

    // (1) Error: must declare a body, because it is not marked 
    // abstract, extern, or partial 
    // bool IFish.Swim(); 

    // (2) Error: the modifier 'abstract' is not valid for this item 
    // abstract bool IFish.Swim(); 

    // (3): If no declaration is provided, compiler says 
    // "WalkingFishCommon does not implement member IFish.Swim()" 
    // {no declaration} 

    // (4) Error: the modifier 'virtual' is not valid for this item 
    // virtual bool IFish.Swim(); 

    // (5) Compiles, but fails to force derived class to implement Swim() 
    bool IFish.Swim() { return true; } 
} 

Ich habe noch nicht herausgefunden, wie das zu machen Compiler glücklich, während immer noch das Ziel erreicht, von WalkingFishCommon abgeleitete Klassen zu zwingen, die Swim() Methode zu implementieren. Besonders verwirrend ist das Delta zwischen (1) und (2), wo der Compiler abwechselnd beschwert, dass Swim() nicht als abstrakt markiert ist und im nächsten Atemzug beklagt, dass es nicht abstrakt markiert werden kann. Interessanter Fehler!

Irgendwelche Hilfe?

+2

Sie könnten eine NotImplementedException in IFish.Swim werfen, obwohl es nicht wirklich das ist, was Sie suchen – BlackBear

+2

Sie müssen die gesamte Schnittstelle implementieren. Sie können eine leere Methode deklarieren und einfach nicht verwenden. – Botonomous

+0

Ok, nun, wenn es nur eine Einschränkung der Sprachsemantik ist, kann ich damit leben. Vielleicht habe ich die Quellen falsch gelesen, die darauf hindeuten, dass dies möglich war ... – Stabledog

Antwort

31

Erklären Sie einfach Swim als abstract und versuchen Sie nicht, explizite Interface-Deklaration dafür zu verwenden (d. H. Entfernen IFish).

abstract class WalkingFishCommon : IFish 
{ 
    public bool CanWalk { get { return true; } } 
    public abstract bool Swim(); 
} 
+0

Nitpick: das ist nicht * ganz * das selbe: jetzt du kann '((WalkingFishCommon) neu SomeFish()). Swim()'. – Jon

+0

Das OP könnte einen guten Grund haben, explizite Implementierung zu verwenden ... –

+1

@ThomasLevesque Und wenn er es tut, werde ich es noch einmal besuchen. Ich denke, es ist wahrscheinlich, dass er keine explizite Schnittstellenimplementierung benötigt, und klar zu versuchen, es zuzulassen, verkompliziert das Problem sehr. – Servy

26

Typischerweise Schnittstellen für jedes Mitglied der Schnittstelle in der Klasse ein öffentliches Mitglieds durch die Definition implizit umgesetzt werden:

class MyFish : IFish 
{ 
    public bool CanWalk { get { return ...; } } 

    public bool Swim() { return ...; } 
} 

Wenn Sie nicht wollen, eine Implementierung für eines dieser Mitglieder zu schaffen, Sie können einfach es abstrakt machen:

abstract class FishBase : IFish 
{ 
    public virtual bool CanWalk { get { return true; } } 

    public abstract bool Swim(); 
} 

Wenn Sie wirklich die Schnittstelle explicitly implementieren müssen, können Sie zwei Mitglieder erstellen: ein abstraktes Mitglied th bei muß von der abgeleiteten Klasse überschrieben werden, und ein Mitglied der Schnittstelle implementiert und das Gespräch mit dem ersten Element Spedition:

abstract class FishBase : IFish 
{ 
    public virtual bool CanWalk { get { return true; } } 

    protected abstract bool Swim(); 

    bool IFish.Swim() { return Swim(); } 
} 
+3

+1 für 'protected abstract' Verwendung –

9

Wenn Sie wirklich nicht explizit die Schnittstelle implementieren müssen, können Sie einfach dies tun könnte:

abstract class WalkingFishCommon : IFish { 
    public abstract bool CanWalk { get; } 
    public abstract bool Swim(); 

} 

Wenn die explizite Implementierung wichtig ist, können Sie das Problem durch die Einführung von geschützten abstrakte Methoden lösen:

abstract class WalkingFishCommon : IFish { 
    bool IFish.CanWalk { get { return CanWalkCore; } } 
    bool IFish.Swim() { return SwimCore(); } 

    protected abstract bool CanWalkCore { get; } 
    protected abstract bool SwimCore(); 

} 
+0

Eine' protected' Methode implementiert keine Schnittstelle implizit, sondern nur eine 'public' Methode. –

+0

Der obere Code wird die IFish-Schnittstelle nicht erfüllen und –

+0

@JeanHominal nicht kompilieren, und wie ist das ein Problem? Die geschützten Methoden sind nicht die Implementierung der Schnittstelle, sie haben nicht einmal den gleichen Namen wie in der Schnittstelle ... –

1

Nicht gerade eine Lösung, sondern kann B.

interface IWalkingFish 
{ 
    bool CanWalk { get; } 
} 

interface ISwimmingFish 
{ 
    bool Swim(); 
} 

interface IFish : ISwimmingFish, IWalkingFish 
{ } 

abstract class WalkingFishCommon : IWalkingFish 
{ 
    bool IWalkingFish.CanWalk { get { return true; } } 
} 

Dann können Sie die verschiedenen Schnittstellen für die abstrakten und konkreten Klassen verwenden.

Verwandte Themen