C #: Абстрактним класам потрібно реалізувати інтерфейси?


131

Мій тестовий код на C #:

namespace DSnA
{
    public abstract class Test : IComparable
    {

    }
}

Результати в наступній помилці компілятора:

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

Оскільки клас Test- це абстрактний клас , чому компілятор вимагає від нього для реалізації інтерфейсу? Чи не повинна ця вимога бути обов'язковою лише для конкретних занять?


Ха-ха. Я написав одне, тоді вирішив змінити. Вибачте. :)
Джоел

2
Грунтуючись на суттєвих коментарях та коментарях до прийнятої відповіді, я вважаю, що голосування приходять через те, як формулюється питання. ОП запитує "чому саме так", що було б поза сферою stackoverflow. Зіткнувшись із цим, питання більше нагадує: "Чи щось мені не вистачає? Чи справді мені потрібно подати реалізацію? Хіба це не перешкоджає тому, що це абстрактний клас?" На це відповідь "Ні, вам не потрібно надавати реалізації (що порушило б призначення абстрактного класу), але ось що вам потрібно зробити, щоб ваша ситуація працювала".
ToolmakerSteve

Я знайшов випадок, коли вам потрібно поставити реалізацію. Саме там інтерфейс має необов’язковий параметр. Якщо ви включите метод як абстрактний в базовий клас, то успадковані класи не будуть компілюватися без необов'язкового параметра (що перемагає призначення необов'язкового параметра). Я просто кидаю NotImplementedException у цьому випадку.
Пол Маккарті

Ігноруйте мій попередній коментар - він не спрацював як очікувалося, принцип найменшого сюрпризу тут не застосовується.
Пол Маккарті

Відповіді:


141

У C # клас, який реалізує інтерфейс, необхідний для визначення всіх членів цього інтерфейсу. Що стосується абстрактного класу, ви просто визначите тих членів із abstractключовим словом:

interface IFoo
{
    void Bar();
}

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

Або кажучи інакше: вам не доведеться "реалізовувати" це (що було б жахливим обмеженням для абстрактних класів); однак у C # вам потрібно сказати компілятору, що ви навмисно передаєте долар конкретним підкласам - і вищевказаний рядок коду показує, як це зробити.

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


2
@Ben Щойно побачив ваш коментар. Ви, мабуть, це вже зрозуміли, але на випадок, якщо комусь це потрібно. Ознайомтеся з явними
Joel

2
@Joel @Ben Я не думаю, що явні інтерфейси можуть працювати з абстрактними класами. У наведеному вище прикладі змініть визначення на Fooна public abstract void IFoo.Bar();і ви отримаєте скарги на те, що "public" та "abstract" не є дійсними модифікаторами.
Даррен Кук

8
Це не відповідає на питання, чому це взагалі потрібно, враховуючи, що це абстрактний клас, і компілятор повинен знати, як заповнити бланк. У Java це не обов'язково, що дозволяє використовувати декілька корисних шаблонів, таких як візерунок декораторів на контейнерах ioc, наприклад Spring / JavaEE (коли вам потрібно прикрасити певний метод керованого інтерфейсу). Ця ж реалізація in.net повинна була б змусити розробників бути дуже багатослівними, особливо на великих інтерфейсах, таких як ISession nhibernate
Sheepy

1
Міксин AspectJ - ще один приклад. Це дозволяє змішати часткові реалізації з багатьох абстрактних класів в єдиний інтерфейс. Кожному абстрактному класу потрібно реалізувати лише той метод, який він хоче реалізувати. Жоден тупий абстрактний метод
котла не перешкоджає

1
@Sheepy - Це правда, але, ІМХО, ви неправильно розумієте, що потрібно запитувачу , і як це, справді, "відповідь". У мене теж було те саме запитання - тому що не було сенсу вимагати виконання програми, тому я застряг. Відповідь: Вам не потрібно " реалізовувати " це, але ось що ви повинні зробити, щоб сказати компілятору, що не збираєтесь його реалізовувати. (Питання, на яке ви [правильно] говорите, що це не відповідь, не було б відповідним стартовим запитанням - воно було б просто закрите як нецільове.)
ToolmakerSteve

10

На відміну від Java, у C #: "абстрактний клас повинен забезпечувати реалізацію всіх членів інтерфейсів, які вказані у списку базового класу класу. Однак абстрактному класу дозволено відображати методи інтерфейсу на абстрактні методи."

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


1
Супер чітка відповідь і чудово, що ви пропонуєте обидві ситуації, оскільки ви також іноді можете захотіти реалізувати поведінку в базовому класі
VinKel

Тут виникає одне запитання: чому ці декларації на шафі C # (що, очевидно, вони є) повинні існувати в абстрактних класах, які в іншому випадку можуть бути стислими та коротшими (таким чином, заплутуючи класи)? У моєму проекті C # є багато абстрактних класів та інтерфейсів - і те, що я роблю протягом більшої частини часу, - це копіювання та вставлення декларацій методів у Visual Studio.
форсберг

5

Їм не потрібно реально реалізовувати інтерфейс .
Методи / властивості інтерфейсу можуть бути абстрактними або навіть віртуальними. Таким чином, це залежить від підкласів, щоб реально їх реалізувати.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.