C #: le classi astratte devono implementare interfacce?


131

Il mio codice di prova in C #:

namespace DSnA
{
    public abstract class Test : IComparable
    {

    }
}

Risultati nel seguente errore del compilatore:

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

Poiché la classe Testè una classe astratta , perché il compilatore lo richiede per implementare l'interfaccia? Questo requisito non dovrebbe essere obbligatorio solo per le classi concrete?


Haha. Ho scritto una cosa e poi ho deciso di cambiarla. Scusate. :)
Joel

2
Sulla base dei voti negativi e dei commenti sulla risposta accettata, credo che i voti negativi derivino dal modo in cui è formulata la domanda. OP chiede "perché è così", che sarebbe al di fuori dell'ambito dello stackoverflow. Avendo incontrato questo me stesso, la domanda è più simile a "Mi sto perdendo qualcosa? Devo davvero fornire implementazioni? Non è ciò che sconfigge il fatto che sia una classe astratta?" A cui la risposta è "No, non devi fornire implementazioni (che violerebbero lo scopo di una classe astratta), ma ecco cosa devi fare per far funzionare la tua situazione".
ToolmakerSteve

Ho trovato un caso in cui devi fornire un'implementazione. È dove l'interfaccia ha un parametro opzionale. Se includi il metodo come astratto nella classe base, le classi ereditate non verranno compilate senza il parametro facoltativo (che vanifica lo scopo di un parametro facoltativo). Ho appena lanciato NotImplementedException in questo caso.
Paul McCarthy,

Ignora il mio commento precedente - non ha funzionato come previsto, il principio della minima sorpresa non si applica qui.
Paul McCarthy,

Risposte:


141

In C #, è necessaria una classe che implementa un'interfaccia per definire tutti i membri di tale interfaccia. Nel caso di una classe astratta, devi semplicemente definire quei membri con la abstractparola chiave:

interface IFoo
{
    void Bar();
}

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

O per dirla in altro modo: non è necessario "implementarlo" (il che sarebbe una terribile limitazione per le classi astratte); tuttavia, in C #, devi dire al compilatore che stai deliberatamente passando il buck a sottoclassi concrete - e la riga di codice sopra mostra come farlo.

I commenti e i voti negativi che lamentano che questa non è una risposta alla domanda mancano di punto. Qualcuno che arriva a Stack Overflow, avendo ricevuto questo errore del compilatore, ma avendo una classe astratta in cui sarebbe un errore fornire un'implementazione, sono bloccati senza una buona soluzione - dovrebbero scrivere metodi di implementazione che generano eccezioni di runtime, un lavoro orrendo - circa - fino a quando non avranno le informazioni di cui sopra. Che sia positivo o negativo che C # richieda questa esplicitazione non rientra nell'ambito di Stack Overflow e non è pertinente alla domanda né a questa risposta.


2
@Ben Ho appena visto il tuo commento. Probabilmente l'hai già capito, ma nel caso qualcun altro ne abbia bisogno. Dai un'occhiata alle implementazioni dell'interfaccia esplicita: msdn.microsoft.com/en-us/library/ms173157.aspx
Joel

2
@Joel @Ben Non credo che interfacce esplicite possano funzionare con classi astratte. Nel codice di esempio sopra riportato, cambia la definizione in Fooin public abstract void IFoo.Bar();e ricevi lamentele sul fatto che "pubblico" e "astratto" non sono modificatori validi.
Darren Cook,

8
Questo non risponde alla domanda sul perché ciò sia addirittura necessario, considerando che si tratta di una classe astratta e il compilatore dovrebbe sapere come riempire il vuoto. In Java ciò non è necessario, il che consente diversi modelli utili come motivi di decorazione su contenitori di ioc, ad esempio Primavera / JavaEE (quando è necessario decorare un particolare metodo di un'interfaccia gestita). La stessa implementazione in.net dovrebbe costringere gli sviluppatori a essere molto prolissi, specialmente su grandi interfacce come ISession di Nhibernate
Sheepy,

1
I mixin di AspectJ sono un altro esempio. Ti consente di mescolare implementazioni parziali di molte classi astratte in un'unica interfaccia. Ogni classe astratta deve solo implementare il metodo che vuole implementare. Nessun idiota stupido metodo astratto si mette in mezzo come succede se
devo

1
@Sheepy - Vero, ma, IMHO, hai frainteso ciò di cui ha bisogno il richiedente e come questa sia, in effetti, una "risposta". Anch'io avevo la stessa domanda - perché non aveva senso essere obbligato a fornire un'implementazione, quindi ero bloccato. La risposta è: non devi " implementarlo ", ma ecco cosa devi fare per dire al compilatore che non lo implementerai. (La domanda a cui [correttamente] dici che questa non è una risposta, non sarebbe una domanda stackoverflow appropriata - sarebbe stata semplicemente chiusa come fuori uso.)
ToolmakerSteve

10

A differenza di Java, in C #: "una classe astratta deve fornire implementazioni di tutti i membri delle interfacce elencate nell'elenco delle classi di base della classe. Tuttavia, una classe astratta è autorizzata a mappare i metodi di interfaccia su metodi astratti".

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


1
Risposta super chiara e ottima per fornire entrambe le situazioni, poiché a volte potresti voler implementare il comportamento nella classe base
VinKel

Una domanda che si pone qui è: perché queste dichiarazioni di C # boilerplate (che ovviamente sono) devono esistere in classi astratte, che altrimenti potrebbero essere concise e più brevi (rovinando così le classi)? Nel mio progetto C # ho molte classi e interfacce astratte - e quello che faccio per la maggior parte del tempo è copiare e incollare le dichiarazioni dei metodi in Visual Studio.
forsberg,

5

Non devono implementare effettivamente l'interfaccia .
I metodi / proprietà dell'interfaccia possono essere astratti o anche virtuali. Quindi spetta alle sottoclassi implementarle effettivamente.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.