Uso l'implementazione esplicita dell'interfaccia per la maggior parte del tempo. Ecco i motivi principali.
Il refactoring è più sicuro
Quando si cambia un'interfaccia, è meglio se il compilatore può controllarla. Questo è più difficile con implementazioni implicite.
Mi vengono in mente due casi comuni:
Aggiunta di una funzione a un'interfaccia, in cui una classe esistente che implementa questa interfaccia ha già un metodo con la stessa firma di quella nuova . Questo può portare a comportamenti inaspettati e mi ha morso parecchie volte. È difficile "vedere" durante il debug perché quella funzione probabilmente non si trova con gli altri metodi di interfaccia nel file (il problema di auto-documentazione menzionato di seguito).
Rimozione di una funzione da un'interfaccia . I metodi implementati implicitamente saranno improvvisamente codice morto, ma i metodi implementati esplicitamente verranno colti da errori di compilazione. Anche se il codice morto è buono da tenere in giro, voglio essere costretto a rivederlo e promuoverlo.
È un peccato che C # non abbia una parola chiave che ci costringe a contrassegnare un metodo come implementazione implicita, quindi il compilatore potrebbe fare i controlli extra. I metodi virtuali non presentano nessuno dei problemi sopra descritti a causa dell'uso obbligatorio di "override" e "new".
Nota: per le interfacce fisse o che cambiano raramente (in genere dalle API del fornitore), questo non è un problema. Per le mie interfacce, tuttavia, non posso prevedere quando / come cambieranno.
È auto-documentante
Se vedo "public bool Execute ()" in una classe, ci vorrà del lavoro extra per capire che fa parte di un'interfaccia. Qualcuno probabilmente dovrà commentarlo dicendo così, o inserirlo in un gruppo di altre implementazioni di interfaccia, il tutto in una regione o commento di raggruppamento dicendo "implementazione di ITask". Ovviamente, funziona solo se l'intestazione del gruppo non è fuori schermo.
Considerando che: 'bool ITask.Execute ()' è chiaro e inequivocabile.
Chiara separazione dell'implementazione dell'interfaccia
Penso che le interfacce siano più "pubbliche" dei metodi pubblici perché sono progettate per esporre solo un po 'della superficie del tipo concreto. Riducono il tipo a una capacità, un comportamento, una serie di tratti, ecc. E nell'implementazione, penso che sia utile mantenere questa separazione.
Mentre guardo il codice di una classe, quando trovo implementazioni esplicite dell'interfaccia, il mio cervello passa alla modalità "contratto di codice". Spesso queste implementazioni semplicemente passano ad altri metodi, ma a volte eseguiranno un ulteriore controllo dello stato / dei parametri, la conversione dei parametri in entrata per soddisfare meglio i requisiti interni o persino la traduzione per scopi di versioning (cioè più generazioni di interfacce tutte puntate verso implementazioni comuni).
(Mi rendo conto che anche i pubblici sono contratti di codice, ma le interfacce sono molto più potenti, specialmente in una base di codici basata sull'interfaccia in cui l'uso diretto di tipi concreti di solito è un segno di codice solo interno).
Correlati: motivo 2 sopra di Jon .
E così via
Inoltre i vantaggi già menzionati in altre risposte qui:
I problemi
Non è tutto divertimento e felicità. Ci sono alcuni casi in cui mi attengo impliciti:
- Tipi di valore, perché ciò richiederà boxe e perf inferiore. Questa non è una regola rigorosa e dipende dall'interfaccia e da come deve essere utilizzata. IComparable? Implicito. IFormattable? Probabilmente esplicito.
- Interfacce di sistema di prova che hanno metodi che vengono spesso chiamati direttamente (come IDisposable.Dispose).
Inoltre, può essere una seccatura fare il casting quando in realtà hai il tipo concreto e vuoi chiamare un metodo di interfaccia esplicita. Mi occupo di questo in due modi:
- Aggiungi i pubblici e fai in modo che i metodi di interfaccia li trasmettano per l'implementazione. In genere accade con interfacce più semplici quando si lavora internamente.
- (Il mio metodo preferito) Aggiungi un
public IMyInterface I { get { return this; } }
(che dovrebbe essere integrato) e chiama foo.I.InterfaceMethod()
. Se più interfacce che richiedono questa capacità, espandi il nome oltre me (nella mia esperienza è raro che io abbia questa necessità).