C #: klasy abstrakcyjne muszą implementować interfejsy?

131

Mój kod testowy w C #:

namespace DSnA
{
    public abstract class Test : IComparable
    {

    }
}

Powoduje następujący błąd kompilatora:

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

Ponieważ klasa Testjest klasą abstrakcyjną , dlaczego kompilator wymaga jej do zaimplementowania interfejsu? Czy ten wymóg nie powinien być obowiązkowy tylko w przypadku zajęć konkretnych?

bguiz
źródło
Ha ha. Napisałem jedną rzecz i postanowiłem to zmienić. Przepraszam. :)
Joel
3
Opierając się na głosach przeciw i komentarzach do przyjętej odpowiedzi, uważam, że głosy przeciwne wynikają ze sposobu sformułowania pytania. OP pyta „dlaczego tak jest”, co byłoby poza zakresem stackoverflow. Kiedy sam się z tym spotkałem, pytanie brzmi bardziej jak: „Czy czegoś mi brakuje? Czy naprawdę muszę dostarczać implementacje? Czy to nie oznacza, że ​​jest to klasa abstrakcyjna?” Na co odpowiedź brzmi: „Nie, nie musisz dostarczać implementacji (co naruszyłoby cel klasy abstrakcyjnej), ale oto, co musisz zrobić, aby Twoja sytuacja zadziałała”.
ToolmakerSteve
Znalazłem przypadek, w którym musisz dostarczyć implementację. Jest to miejsce, w którym interfejs ma opcjonalny parametr. Jeśli włączysz metodę jako abstrakcyjną do klasy bazowej, to odziedziczone klasy nie będą się kompilować bez opcjonalnego parametru (co jest sprzeczne z celem opcjonalnego parametru). Po prostu wrzucam NotImplementedException w tym przypadku.
Paul McCarthy
Zignoruj ​​mój poprzedni komentarz - nie zadziałał zgodnie z oczekiwaniami, zasada najmniejszego zaskoczenia nie ma tutaj zastosowania.
Paul McCarthy

Odpowiedzi:

144

W języku C # klasa implementująca interfejs jest wymagana do zdefiniowania wszystkich członków tego interfejsu. W przypadku klasy abstrakcyjnej wystarczy zdefiniować te elementy za pomocą abstractsłowa kluczowego:

interface IFoo
{
    void Bar();
}

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

Albo inaczej: nie musisz tego „implementować” (co byłoby okropnym ograniczeniem klas abstrakcyjnych); jednak w C # musisz powiedzieć kompilatorowi , że celowo przekazujesz złotówkę konkretnym podklasom - a powyższy wiersz kodu pokazuje, jak to zrobić.

Komentarze i głosy przeciw, narzekające, że nie jest to odpowiedź na pytanie, nie mają sensu. Ktoś, kto przychodzi do Stack Overflow, otrzymawszy ten błąd kompilatora, ale mając klasę abstrakcyjną, w której dostarczenie implementacji byłoby błędem, utknął bez dobrego rozwiązania - musiałby napisać metody implementacji, które rzucałyby wyjątki w czasie wykonywania, horrendalna praca -okoła - dopóki nie uzyskają powyższych informacji. Czy to dobrze, czy źle, że C # wymaga tej jawności, znajduje się poza zakresem przepełnienia stosu i nie ma znaczenia dla pytania ani tej odpowiedzi.

Joel
źródło
2
@Ben Właśnie zobaczyłem Twój komentarz. Prawdopodobnie już to rozgryzłeś, ale na wypadek, gdyby ktoś tego potrzebował. Sprawdź jawne implementacje interfejsu: msdn.microsoft.com/en-us/library/ms173157.aspx
Joel
2
@Joel @Ben Nie sądzę, aby jawne interfejsy działały z klasami abstrakcyjnymi. W powyższym przykładowym kodzie zmień definicję Foona, public abstract void IFoo.Bar();a otrzymasz skargi, że „public” i „abstract” nie są poprawnymi modyfikatorami.
Darren Cook
8
To nie odpowiada na pytanie, dlaczego jest to w ogóle konieczne, biorąc pod uwagę, że jest to klasa abstrakcyjna, a kompilator powinien wiedzieć, jak wypełnić puste miejsce. W Javie nie jest to konieczne, co pozwala na kilka użytecznych wzorców, takich jak wzorzec dekoratora w kontenerach ioc, np. Spring / JavaEE (gdy trzeba ozdobić określoną metodę zarządzanego interfejsu). Ta sama implementacja w.net musiałaby zmusić deweloperów do bardzo rozwlekłej strony, szczególnie w przypadku dużych interfejsów, takich jak ISession nhibernate
Sheepy.
1
Innym przykładem są mixiny AspectJ. Umożliwia mieszanie częściowych implementacji z wielu klas abstrakcyjnych w jednym interfejsie. Każda klasa abstrakcyjna musi tylko zaimplementować metodę, którą chce zaimplementować. Żadna głupia abstrakcyjna metoda nie przeszkadza, jak ma to miejsce, jeśli mam odtworzyć tę samą funkcjonalność w .net
Sheepy
1
@Sheepy - Prawda, ale IMHO, źle rozumiesz, czego potrzebuje osoba pytająca i dlaczego jest to rzeczywiście „odpowiedź”. Ja też miałem to samo pytanie - ponieważ wymaganie dostarczenia implementacji nie miało sensu, więc utknąłem. Odpowiedź brzmi: nie musisz tego „ implementować ” - ale oto, co musisz zrobić, aby powiedzieć kompilatorowi, że nie zamierzasz go zaimplementować. (Pytanie, na które [poprawnie] powiesz, że nie jest to odpowiedź, nie byłoby odpowiednim pytaniem o
przepełnienie stosu
10

W przeciwieństwie do Javy, w języku C #: „Klasa abstrakcyjna musi zapewniać implementacje wszystkich elementów członkowskich interfejsów wymienionych na liście klas bazowych klasy. Jednak klasa abstrakcyjna może mapować metody interfejsu na metody abstrakcyjne”.

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

00jt
źródło
1
Super jasne odpowiedź i wielkie, że podasz obie sytuacje, jak również może czasami chcą wprowadzić zachowanie w klasie bazowej
Vinkel
Pojawia się tutaj pytanie: dlaczego te standardowe deklaracje języka C # (którymi są oczywiście) muszą istnieć w klasach abstrakcyjnych, które w przeciwnym razie mogłyby być zwięzłe i krótsze (w ten sposób zepsuć klasy)? W moim projekcie C # mam wiele abstrakcyjnych klas i interfejsów - a to, co robię przez większość czasu, to kopiowanie i wklejanie deklaracji metod w Visual Studio.
forsberg
5

Nie muszą faktycznie implementować interfejsu .
Metody / właściwości interfejsu mogą być abstrakcyjne lub nawet wirtualne. Tak więc od podklas zależy, czy faktycznie je zaimplementują.

ntziolis
źródło