C #: абстрактные классы должны реализовывать интерфейсы?

131

Мой тестовый код в C #:

namespace DSnA
{
    public abstract class Test : IComparable
    {

    }
}

Результатом является следующая ошибка компилятора:

error CS0535: 'DSnA.Test' does not implement interface member
'System.IComparable.CompareTo(object)'

Поскольку класс Testявляется абстрактным классом , почему компилятор требует его реализации интерфейса? Разве это требование не должно быть обязательным только для конкретных классов?

bguiz
источник
Ха - ха. Я написал одну вещь, а затем решил изменить это. Сожалею. :)
Джоэл
2
Основываясь на отрицательных голосах и комментариях к принятому ответу, я полагаю, что отрицательные голоса происходят из-за способа, которым сформулирован вопрос. OP спрашивает, «почему это так», что выходит за рамки возможностей stackoverflow. Столкнувшись с этим сам, вопрос больше напоминает: «Я что-то упустил? Мне действительно нужно предоставлять реализации? Разве это не умаляет смысла быть абстрактным классом?» На что ответ «Нет, вам не нужно предоставлять реализации (которые нарушали бы цель абстрактного класса), но вот что вы должны сделать, чтобы ваша ситуация работала».
ToolmakerSteve
Я нашел случай, когда вы должны предоставить реализацию. Это где интерфейс имеет необязательный параметр. Если вы включите метод в качестве абстрактного в базовый класс, то унаследованные классы не будут компилироваться без необязательного параметра (который отрицает назначение необязательного параметра). Я просто выбрасываю NotImplementedException в этом случае.
Пол Маккарти
Не обращайте внимания на мой предыдущий комментарий - он не сработал, как ожидалось, принцип наименьшего удивления здесь не применим.
Пол Маккарти

Ответы:

141

В C # класс, реализующий интерфейс, необходим для определения всех членов этого интерфейса. В случае абстрактного класса вы просто определяете эти члены с помощью abstractключевого слова:

interface IFoo
{
    void Bar();
}

abstract class Foo : IFoo
{
    public abstract void Bar();
}

Или, говоря иначе: вам не нужно «реализовывать» это (что было бы ужасным ограничением для абстрактных классов); тем не менее, в C # вы должны сообщить компилятору, что вы сознательно передаёте деньги конкретным подклассам - и приведенная выше строка кода показывает, как это сделать.

Комментарии и отзывы, жалующиеся на то, что это не ответ на вопрос, упускают суть. Кто-то, приходящий в Stack Overflow, получив эту ошибку компилятора, но имея абстрактный класс, в котором было бы ошибочно предоставлять реализацию, застрял без хорошего решения - ему пришлось бы писать методы реализации, которые вызывали исключения во время выполнения, - ужасная работа Вокруг - пока они не имеют вышеуказанную информацию. Хорошо это или плохо, что C # требует этой явности, выходит за рамки переполнения стека и не имеет отношения ни к вопросу, ни к этому ответу.

Joel
источник
2
@Ben Только что увидел твой комментарий. Вы, наверное, уже поняли это, но в случае, если это кому-то еще нужно. Ознакомьтесь с явными
Джоэл
2
@Joel @Ben Я не думаю, что явные интерфейсы могут работать с абстрактными классами. В приведенном выше примере кода измените определение Fooна, public abstract void IFoo.Bar();и вы получите жалобы на то, что «public» и «abstract» не являются допустимыми модификаторами.
Даррен Кук
8
Это не отвечает на вопрос, почему это вообще необходимо, учитывая, что это абстрактный класс, и компилятор должен знать, как заполнить пробел. В Java это не обязательно, что позволяет использовать несколько полезных шаблонов, таких как шаблон декоратора в контейнерах ioc, например Spring / JavaEE (когда вам нужно украсить определенный метод управляемого интерфейса). Та же самая реализация в .net должна была бы заставить разработчиков быть очень многословными, особенно на больших интерфейсах, таких как ISession nhibernate
Sheepy
1
Mixin AspectJ является еще одним примером. Это позволяет смешивать частичные реализации многих абстрактных классов в единый интерфейс. Каждый абстрактный класс должен реализовывать только тот метод, который он хочет реализовать. Никакой тупой шаблон абстрактного метода не мешает, как в случае, если я собираюсь воссоздать ту же функциональность в .net
Sheepy
1
@Sheepy - Верно, но, ИМХО, вы неправильно понимаете, что нужно спрашивающему , и как это, действительно, «ответ». У меня также был тот же вопрос - потому что не было смысла требовать предоставления реализации, поэтому я застрял. Ответ таков: вам не нужно « реализовывать » его, но вот что вам нужно сделать, чтобы сообщить компилятору, что вы не собираетесь его реализовывать. (Вопрос , который вы [правильно] говорят , что это не ответ, не был бы соответствующий StackOverflow вопрос -. Он бы просто был закрыт , как от-цели)
ToolmakerSteve
10

В отличие от Java, в C #: «абстрактный класс должен обеспечивать реализации всех членов интерфейсов, перечисленных в списке базовых классов этого класса. Однако абстрактному классу разрешено отображать методы интерфейса на абстрактные методы».

https://msdn.microsoft.com/en-us/library/Aa664595(v=VS.71).aspx

00jt
источник
1
Супер четкий ответ и здорово, что вы предоставляете обе ситуации, так как вы также можете иногда захотеть реализовать поведение в базовом классе
VinKel
Возникает один вопрос: почему эти шаблонные объявления C # (которые, очевидно, таковыми являются) должны существовать в абстрактных классах, которые в противном случае могли бы быть краткими и более короткими (таким образом, запутывая классы)? В моем проекте на C # у меня есть много абстрактных классов и интерфейсов, и большую часть времени я занимаюсь копированием и вставкой объявлений методов в Visual Studio.
Форсберг
5

Им не нужно реализовывать интерфейс .
Методы / свойства интерфейса могут быть абстрактными или даже виртуальными. Таким образом, дело до подклассов, чтобы фактически реализовать их.

ntziolis
источник