Perché sia ​​la class astratta che l’interfaccia esistono in C #?

Perché sia ​​la class astratta che l’interfaccia esistono in C # se possiamo ottenere la caratteristica dell’interfaccia rendendo astratti tutti i membri della class.

È perché:

  1. L’interfaccia esiste per avere ereditarietà multipla
  2. Ha senso avere un’interfaccia perché la funzione CAN-DO dell’object deve essere inserita in una class astratta di base piuttosto dell’interfaccia.

Si prega di precisare

Bene, una class astratta può specificare qualche implemetazione, ma di solito non tutto. (Detto ciò, è perfettamente ansible fornire una class astratta senza membri astratti, ma molti virtuali con implementazioni “no-op”). Un’interfaccia non fornisce implementazione, ma solo un contratto.

Si potrebbe certamente affermare che se fosse permessa l’ereditarietà multipla delle classi, le interfacce sarebbero in gran parte inutili.

Personalmente non rimango fermo sull’intera “is-a” vs “can-do” per l’ereditarietà. Non mi dà mai una buona intuizione su cosa fare, semplicemente giocando con idee diverse e vedendo quali si sentono più flessibili. (Poi di nuovo, sono molto un tipo di “composizione di favore rispetto all’eredità” …)

EDIT: proprio come il modo più conveniente di ribaltare il terzo punto di lbushkin nel suo commento … puoi sovrascrivere un metodo astratto con un metodo non virtuale (in termini di non poterlo sovrascrivere ulteriormente) sigillandolo:

public abstract class AbstractBase { public abstract void Foo(); } public class Derived : AbstractBase { public sealed override void Foo() {} } 

Le classi derivate da Derived non possono ignorare Foo ulteriormente.

Non sto in alcun modo suggerendo che voglio un’eredità multipla di implementazione – ma se ce l’avessimo (insieme alla sua complessità) allora una class astratta che conteneva solo metodi astratti avrebbe realizzato quasi tutto ciò che fa un’interfaccia. (C’è una questione di implementazione esplicita dell’interfaccia, ma questo è tutto quello che posso pensare al momento.)

Non è una domanda banale, è una domanda molto buona e chiedo sempre a tutti i candidati che intervisto.
In poche parole – una class base astratta definisce una gerarchia di tipi mentre un’interfaccia definisce un contratto.

Puoi vederlo come è un vs implementa a .
Ad esempio, l’ Account potrebbe essere un account di base astratto perché potresti avere un conto di CheckingAccount , un conto di SavingsAccount , ecc. che derivano dall’account di class di base astratto. Le astratte classi di base possono anche contenere metodi, proprietà e campi non astratti come qualsiasi class normale. Tuttavia, le interfacce contengono solo metodi e proprietà astratti che devono essere implementati.

c # deriviamo solo da una class base – l’ereditarietà singola come java. Tuttavia è ansible implementare tutte le interfacce che si desidera – questo perché un’interfaccia è solo un contratto che la class promette di implementare.

Quindi, se avessi una class SourceFile mia class potrebbe scegliere di implementare ISourceControl che dice “Prometto fedelmente di implementare i metodi e le proprietà che ISourceControl richiede”

Questa è una grande area e probabilmente degna di un post migliore di quella che ho dato, ma sono a corto di tempo, ma spero che aiuti!

Entrambi esistono perché sono due cose molto diverse. Le classi astratte consentono l’implementazione e le interfacce no. Un’interfaccia è molto utile in quanto mi consente di dire qualcosa sul tipo che sto costruendo (è serializzabile, è commestibile, ecc.) Ma non mi permette di definire alcuna implementazione per i membri che definisco.

Una class astratta è più potente di un’interfaccia nel senso che mi consente di creare un’interfaccia di ereditarietà tramite membri astratti e virtuali, ma anche di fornire una sorta di implementazione di base o predefinita, se così scelgo. Come lo sa Spiderman, tuttavia, con quel grande potere derivano grandi responsabilità in quanto una class astratta è architettonicamente più fragile.

Nota a margine : Qualcosa di interessante da notare è che Vance Morrrison (del team CLR) ha speculato sull’aggiunta di implementazioni di metodi predefiniti alle interfacce in una versione futura del CLR. Ciò confonderebbe molto la distinzione tra un’interfaccia e una class astratta. Vedi questo video per i dettagli.

Un motivo importante per entrambi i meccanismi esiste perché c # .NET consente solo l’ereditarietà singola, non l’ereditarietà multipla come il C ++. L’ereditarietà della class consente di ereditare l’implementazione da un solo punto; tutto il resto deve essere realizzato mediante l’implementazione di interfacce.

Ad esempio, supponiamo di creare una class, come la sottoclass Car e I in tre sottoclassi, RearWheelDrive, FrontWheelDrive e AllWheelDrive. Ora decido che ho bisogno di tagliare le mie classi su un diverso “asse”, come quelli con gli antipasti a pulsante e quelli senza. Voglio che tutti i pulsanti avviino le macchine con un metodo “PushStartButton ()” e le macchine senza pulsante abbiano un metodo “TurnKey ()” e voglio essere in grado di trattare gli oggetti Car (con riferimento all’avvio) indipendentemente da quale sottoclass loro sono. Posso definire le interfacce che possono essere implementate dalle mie classi, come IPushButtonStart e IKeyedIgnition, quindi ho un modo comune per gestire i miei oggetti che differiscono in modo indipendente dalla singola class base da cui deriva ciascuna.

Hai già dato una buona risposta. Penso che la tua seconda risposta sia la vera ragione. Se volessi creare un object Comprado, non avrei dovuto derivare da una class di base comparabile. se pensi a tutte le interfacce, pensa a tutte le permutazioni che avresti dovuto gestire con le interfacce di base come IComparable.

Le interfacce ci consentono di definire un contratto attorno al comportamento esposto pubblicamente fornito da un object. Le classi astratte consentono di definire sia il comportamento che l’implementazione, che è una cosa molto diversa.

Le interfacce esistono per fornire una class senza alcuna implementazione, in modo che .NET possa fornire supporto per l’ereditarietà multipla sicura e funzionale in un ambiente gestito.

Un’interfaccia definisce un contratto che una class di implementazione deve soddisfare; è un modo per affermare che “questo fa ciò”. Una class astratta è un’implementazione parziale di una class che è per definizione incompleta e che deve essere completata con un derviation. Sono cose molto diverse.

Una class abstract può avere un’implementazione mentre interface ti consente solo di creare un contratto che gli implementatori devono seguire. Con le classi astratte è ansible fornire un comportamento comune alle loro sottoclassi che non è ansible con le interfacce.

Servono due scopi distintamente diversi.

Le classi astratte forniscono un modo per avere un object ereditato da un contratto definito, oltre a consentire di specificare il comportamento nella class base. Questo, da un punto di vista teorico, fornisce una relazione IS-A , in quanto la class concreta IS-A specifica un tipo di class base.

Le interfacce consentono alle classi di definire un (o più di un) contratto che soddisfano. Consentono un ACTS-AS o “possono essere usati come un” tipo di relazione, in contrapposizione all’ereditarietà diretta. Questo è il motivo per cui, in genere, le interfacce useranno un aggettivo come nome (IDisposable) anziché un nome.

Un’interfaccia è usata per ciò che una class può fare, ma è anche usata per hide alcune cose che una class può fare.

Ad esempio l’interfaccia IEnumerable descrive che una class può iterare attraverso i suoi membri, ma limita anche l’accesso a questa singola abilità. Un List può anche accedere agli elementi per indice, ma quando vi si accede tramite l’interfaccia IEnumerable , si conosce solo la capacità di iterare i membri.

Se un metodo accetta l’interfaccia IEnumerable come parametro, significa che è solo interrotto nella possibilità di scorrere i membri. Puoi usare diverse classi con questa abilità (come una List o una matrice T[] ) senza la necessità di un metodo per ogni class.

Non solo un metodo può accettare diverse classi che implementano un’interfaccia, è ansible creare nuove classi che implementano l’interfaccia e il metodo accetterà volentieri anche quelle.

Considera di avere una class Fruit derivata da due bambini ( Apple e Banana ) come mostrato di seguito:

 class Fruit { public virtual string GetColor() { return string.Empty; } } class Apple : Fruit { public override string GetColor() { return "Red"; } } class Banana : Fruit { public override string GetColor() { return "Yellow"; } } 

Abbiamo un’interfaccia esistente IConeable in C # . Questa interfaccia ha un singolo metodo come mostrato di seguito, una class che implementa questa interfaccia garantisce che possa essere clonata:

 public interface ICloneable { object Clone(); } 

Ora se voglio rendere clonabile la mia class Apple (non la class Banana ), posso semplicemente implementare ICloneable in questo modo:

  class Apple : Fruit , ICloneable { public object Clone() { // add your code here } public override string GetColor() { return "Red"; } } 

Considerando ora la tua argomentazione sulla pura class astratta, se C # avesse una class astratta pura dire Clonable invece di interfaccia IClonable come questa:

 abstract class Clonable { public abstract object Clone(); } 

Potresti ora rendere clonabile la tua class Apple ereditando l’astratta Clonabile invece di IClonable ? come questo:

 // Error: Class 'Apple' cannot have multiple base classs: 'Fruit' & 'Clonable' class Apple : Fruit, Clonable { public object Clone() { // add your code here } public override string GetColor() { return "Red"; } } 

No, non puoi, perché una class non può derivare da più classi.