Как удовлетворить компилятор, когда только частично реализует интерфейс с абстрактным классом?
У меня есть интерфейс с именем IFish
. Я хочу получить его с абстрактным классом (WalkingFishCommon
), который обеспечивает неполную реализацию, так что классы, полученные из WalkingFishCommon
, не должны реализовывать свойство CanWalk
:
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; }
}
Я еще не обнаружил, как сделать компилятор счастливым, но все еще добивается цели принуждения классов, полученных от WalkingFishCommon, для реализации метода Swim()
. Особенно непонятным является дельта между (1) и (2), где компилятор чередуется между жалобами на то, что Swim()
не обозначен абстрактно, и в следующем дыхании жалуется, что он не может быть помечен как абстрактный. Интересная ошибка!
Любая помощь?
Ответы
Ответ 1
Просто объявите Swim
как abstract
и не пытайтесь использовать для него явное объявление интерфейса (т.е. удалить IFish
).
abstract class WalkingFishCommon : IFish
{
public bool CanWalk { get { return true; } }
public abstract bool Swim();
}
Ответ 2
Как правило, интерфейсы реализуются неявно, определяя открытый член в классе для каждого члена интерфейса:
class MyFish : IFish
{
public bool CanWalk { get { return ...; } }
public bool Swim() { return ...; }
}
Если вы не хотите предоставлять реализацию для одного из этих членов, вы можете просто сделать его абстрактным:
abstract class FishBase : IFish
{
public virtual bool CanWalk { get { return true; } }
public abstract bool Swim();
}
Если вам действительно нужно реализовать интерфейс явно, вы можете создать два члена: один абстрактный элемент, который должен быть переопределен производным классом, и один член реализует интерфейс и переадресовывает вызов первому члену:
abstract class FishBase : IFish
{
public virtual bool CanWalk { get { return true; } }
protected abstract bool Swim();
bool IFish.Swim() { return Swim(); }
}
Ответ 3
Если вам действительно не нужно явно реализовывать интерфейс, вы можете просто сделать это:
abstract class WalkingFishCommon : IFish {
public abstract bool CanWalk { get; }
public abstract bool Swim();
}
Если явная реализация важна, вы можете решить эту проблему, введя защищенные абстрактные методы:
abstract class WalkingFishCommon : IFish {
bool IFish.CanWalk { get { return CanWalkCore; } }
bool IFish.Swim() { return SwimCore(); }
protected abstract bool CanWalkCore { get; }
protected abstract bool SwimCore();
}
Ответ 4
Не совсем решение, но, возможно, вы могли бы сделать что-то вроде
interface IWalkingFish
{
bool CanWalk { get; }
}
interface ISwimmingFish
{
bool Swim();
}
interface IFish : ISwimmingFish, IWalkingFish
{ }
abstract class WalkingFishCommon : IWalkingFish
{
bool IWalkingFish.CanWalk { get { return true; } }
}
Затем вы можете использовать разные интерфейсы для абстрактных и конкретных классов.