Interfacce C #. Implementazione implicita contro implementazione esplicita


632

Quali sono le differenze nell'implementazione delle interfacce in modo implicito ed esplicito in C #?

Quando dovresti usare implicito e quando dovresti usare esplicito?

Ci sono pro e / o contro l'uno o l'altro?


Le linee guida ufficiali di Microsoft (dalle Linee guida per la progettazione del framework della prima edizione ) affermano che l' uso di implementazioni esplicite non è raccomandato , poiché fornisce al codice un comportamento imprevisto.

Penso che questa linea guida sia molto valida in un periodo pre-IoC , quando non si passano le cose come interfacce.

Qualcuno potrebbe toccare anche questo aspetto?


Leggi l'articolo completo sulle interfacce C #: planetofcoders.com/c-interfaces
Gaurav Agrawal,

Sì, le interfacce esplicite dovrebbero essere evitate e un approccio più professionale dovrebbe implementare l'ISP (principio di segregazione dell'interfaccia): ecco un articolo dettagliato sullo stesso codeproject.com/Articles/1000374/…
Shivprasad Koirala,

Risposte:


492

Implicito è quando definisci la tua interfaccia tramite un membro della tua classe. È esplicito quando si definiscono metodi all'interno della propria classe sull'interfaccia. So che sembra confuso, ma ecco cosa intendo: IList.CopyTosarebbe implicitamente implementato come:

public void CopyTo(Array array, int index)
{
    throw new NotImplementedException();
}

ed esplicitamente come:

void ICollection.CopyTo(Array array, int index)
{
    throw new NotImplementedException();
}

La differenza è che l'implementazione implicita ti consente di accedere all'interfaccia attraverso la classe che hai creato lanciando l'interfaccia come quella classe e come l'interfaccia stessa. L'implementazione esplicita ti consente di accedere all'interfaccia solo lanciandola come interfaccia stessa.

MyClass myClass = new MyClass(); // Declared as concrete class
myclass.CopyTo //invalid with explicit
((IList)myClass).CopyTo //valid with explicit.

Uso esplicitamente principalmente per mantenere pulita l'implementazione o quando ho bisogno di due implementazioni. Indipendentemente da ciò, lo uso raramente.

Sono sicuro che ci sono più motivi per usare / non usare espliciti che altri pubblicheranno.

Vedi il prossimo post in questa discussione per un eccellente ragionamento dietro ciascuno.


8
So che questo post è vecchio ma l'ho trovato molto utile - una cosa da notare se non è chiaro perché non era per me era che nell'esempio quello implicito ha la publicparola chiave ... altrimenti otterrai un errore
jharr100,

Il CLR di Jeffrey Richter tramite C # 4 ed il 13 mostra un esempio in cui il casting non è necessario: internal struct SomeValueType: IComparable {private Int32 m_x; public SomeValueType (Int32 x) {m_x = x; } public Int32 CompareTo (SomeValueType other) {...);} Int32 IComparable.CompareTo (Object other) {return CompareTo ((SomeValueType) altro); }} public static void Main () {SomeValueType v = new SomeValueType (0); Object o = new Object (); Int32 n = v.CompareTo (v); // No boxing n = v.CompareTo (o); // errore di compilazione}
Andy Dent,

1
Oggi ho riscontrato una situazione rara che ha RICHIESTO l'uso di un'interfaccia esplicita: una classe con un campo generato da un generatore di interfaccia che crea il campo come privato (Xamarin indirizzato a iOS, utilizzando lo storyboard iOS). E un'interfaccia in cui aveva senso esporre quel campo (di sola lettura). Avrei potuto cambiare il nome del getter nell'interfaccia, ma il nome esistente era il nome più logico per l'oggetto. Così, invece ho fatto un'implementazione esplicita riferendosi al campo privato: UISwitch IScoreRegPlayerViewCell.markerSwitch { get { return markerSwitch; } }.
ToolmakerSteve

1
Gli orrori della programmazione. Bene, ben ridimensionato!
Liquid Core,

1
@ToolmakerSteve un'altra situazione (piuttosto più comune) che richiede l'implementazione esplicita di almeno un membro dell'interfaccia è l'implementazione di più interfacce che hanno membri con la stessa firma ma tipi di restituzione diversi. Ciò può accadere a causa di eredità di interfaccia, come si fa con IEnumerator<T>.Current, IEnumerable<T>.GetEnumerator()e ISet<T>.Add(T). Questo è menzionato in un'altra risposta .
phoog

201

La definizione implicita sarebbe semplicemente aggiungere i metodi / proprietà, ecc. Richiesti dall'interfaccia direttamente alla classe come metodi pubblici.

La definizione esplicita impone che i membri vengano esposti solo quando si lavora direttamente con l'interfaccia e non l'implementazione sottostante. Questo è preferito nella maggior parte dei casi.

  1. Lavorando direttamente con l'interfaccia, non stai riconoscendo e accoppiando il codice all'implementazione sottostante.
  2. Nel caso in cui tu abbia già, per esempio, un nome di proprietà pubblica nel tuo codice e desideri implementare un'interfaccia che ha anche una proprietà Name, farlo esplicitamente manterrà i due separati. Anche se avessero fatto la stessa cosa, avrei comunque delegato la chiamata esplicita alla proprietà Name. Non si sa mai, potresti voler cambiare il modo in cui Nome funziona per la classe normale e come Nome, la proprietà dell'interfaccia funziona in seguito.
  3. Se implementi un'interfaccia in modo implicito, la tua classe ora espone nuovi comportamenti che potrebbero essere rilevanti solo per un client dell'interfaccia e significa che non stai mantenendo le tue classi abbastanza sintetiche (la mia opinione).

2
Fai alcuni buoni punti qui. specialmente A. Di solito passo le mie lezioni come interfaccia, ma non ci ho mai pensato davvero da quella prospettiva.
Mattlant,

5
Non sono sicuro di essere d'accordo con il punto C. Un oggetto Cat potrebbe implementare IEatable ma Eat () è una parte fondamentale delle cose. Ci sarebbero casi in cui si vorrebbe semplicemente chiamare Eat () su un gatto quando si utilizza l'oggetto 'raw' anziché tramite l'interfaccia IEatable, no?
LegendLength,

59
Conosco alcuni posti in cui Catè davvero IEatablesenza obiezioni.
Humberto

26
Non sono completamente d'accordo con quanto sopra, e direi che l'uso di interfacce esplicite è la ricetta del disastro e non OOP o OOD per loro definizione (vedi la mia risposta sul polimorfismo)
Valentin Kuzub,


68

Oltre alle eccellenti risposte già fornite, ci sono alcuni casi in cui è richiesta un'implementazione esplicita affinché il compilatore sia in grado di capire cosa è necessario. Dai un'occhiata al IEnumerable<T>primo esempio che probabilmente verrà fuori abbastanza spesso.

Ecco un esempio:

public abstract class StringList : IEnumerable<string>
{
    private string[] _list = new string[] {"foo", "bar", "baz"};

    // ...

    #region IEnumerable<string> Members
    public IEnumerator<string> GetEnumerator()
    {
        foreach (string s in _list)
        { yield return s; }
    }
    #endregion

    #region IEnumerable Members
    IEnumerator IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }
    #endregion
}

Qui, IEnumerable<string>implementa IEnumerable, quindi anche noi dobbiamo farlo. Ma aspetta, sia la versione generica che quella normale implementano entrambe le funzioni con la stessa firma del metodo (C # ignora il tipo restituito per questo). Questo è completamente legale e va bene. Come risolve il compilatore quale utilizzare? Ti costringe ad avere solo, al massimo, una definizione implicita, quindi può risolvere tutto ciò di cui ha bisogno.

vale a dire.

StringList sl = new StringList();

// uses the implicit definition.
IEnumerator<string> enumerableString = sl.GetEnumerator();
// same as above, only a little more explicit.
IEnumerator<string> enumerableString2 = ((IEnumerable<string>)sl).GetEnumerator();
// returns the same as above, but via the explicit definition
IEnumerator enumerableStuff = ((IEnumerable)sl).GetEnumerator();

PS: Il piccolo pezzo di riferimento indiretto nella definizione esplicita di IEnumerable funziona perché all'interno della funzione il compilatore sa che il tipo effettivo della variabile è un StringList, ed è così che risolve la chiamata di funzione. Un piccolo fatto per l'implementazione di alcuni degli strati di astrazione che alcune delle interfacce core di .NET sembrano aver accumulato.


5
@Tassadaque: dopo 2 anni, tutto ciò che posso dire è "Buona domanda". Non ne ho idea, tranne forse che ho copiato quel codice da qualcosa su cui stavo lavorando abstract.
Matthew Scharley,

4
@Tassadaque, hai ragione, ma penso che il punto del post di Matthew Scharley sopra non sia perso.
funkymushroom

35

Per citare Jeffrey Richter dal CLR via C #
( EIMI significa E Xplicit ho nterface M etodo I ATTUAZIONE)

È di fondamentale importanza per te comprendere alcune ramificazioni che esistono quando si utilizzano gli EIMI. E a causa di queste ramificazioni, dovresti cercare di evitare il più possibile gli EIMI. Fortunatamente, le interfacce generiche ti aiutano a evitare un po 'di EIMI. Ma potrebbero esserci ancora momenti in cui dovrai utilizzarli (come implementare due metodi di interfaccia con lo stesso nome e la stessa firma). Ecco i grandi problemi con gli EIMI:

  • Non esiste documentazione che spieghi come un tipo implementa specificamente un metodo EIMI e non esiste supporto IntelliSense di Microsoft Visual Studio .
  • Le istanze del tipo di valore vengono inscatolate quando vengono trasmesse a un'interfaccia.
  • Un EIMI non può essere chiamato da un tipo derivato.

Se si utilizza un riferimento all'interfaccia QUALSIASI catena virtuale può essere esplicitamente sostituita con EIMI su qualsiasi classe derivata e quando un oggetto di tale tipo viene trasmesso all'interfaccia, la catena virtuale viene ignorata e viene chiamata l'implementazione esplicita. È tutt'altro che polimorfismo.

Gli EIMI possono anche essere usati per nascondere membri dell'interfaccia non fortemente tipizzati dalle implementazioni delle interfacce Framework di base come IEnumerable <T> in modo che la tua classe non esponga direttamente un metodo non fortemente tipizzato, ma è sintatticamente corretto.


2
La reimplementazione delle interfacce, sebbene legale, è generalmente dubbia nella migliore delle ipotesi. Le implementazioni esplicite dovrebbero generalmente essere collegate a un metodo virtuale direttamente o tramite una logica di wrapping che dovrebbe essere vincolante per le classi derivate. Sebbene sia certamente possibile utilizzare le interfacce in modi ostili alle convenzioni OOP appropriate, ciò non significa che non possano essere utilizzate meglio.
supercat,

4
@Valentin Cosa significano EIMI e IEMI?
Dzienny,

Implementazione esplicita del metodo di interfaccia
scobi

5
-1 per "Generalmente vedo le interfacce come funzionalità OOP Semi (nella migliore delle ipotesi), fornisce ereditarietà, ma non fornisce un vero polimorfismo." Sono fortemente in disaccordo. Al contrario, le interfacce riguardano tutto il polimorfismo e non riguardano principalmente l'eredità. Attribuiscono più classificazioni a un tipo. Evita IEMI, quando puoi, e delega, come suggerito da @supercat, quando non puoi. Non evitare le interfacce.
Aluan Haddad,

1
"Un EIMI non può essere chiamato da un tipo derivato." << COSA? Non è vero. Se implemento esplicitamente un'interfaccia su un tipo, quindi derivo da quel tipo, posso ancora lanciarlo sull'interfaccia per chiamare il metodo, esattamente come dovrei fare per il tipo su cui è implementato. Quindi non sono sicuro di cosa stai parlando. Anche all'interno del tipo derivato, posso semplicemente trasmettere "this" all'interfaccia in questione per raggiungere il metodo esplicitamente implementato.
Triynko,

34

Motivo n. 1

Tendo a utilizzare l'implementazione esplicita dell'interfaccia quando desidero scoraggiare la "programmazione per un'implementazione" ( Principi di progettazione dai modelli di progettazione ).

Ad esempio, in un'applicazione Web basata su MVP :

public interface INavigator {
    void Redirect(string url);
}

public sealed class StandardNavigator : INavigator {
    void INavigator.Redirect(string url) {
        Response.Redirect(url);
    }
}

Ora un'altra classe (come un presentatore ) ha meno probabilità di dipendere dall'implementazione di StandardNavigator e più probabilmente di dipendere dall'interfaccia INavigator (poiché l'implementazione dovrebbe essere trasmessa a un'interfaccia per utilizzare il metodo Redirect).

Motivo n. 2

Un altro motivo per cui potrei seguire un'implementazione esplicita dell'interfaccia sarebbe quello di mantenere più pulita l'interfaccia "predefinita" di una classe. Ad esempio, se stavo sviluppando un controllo server ASP.NET , potrei volere due interfacce:

  1. L'interfaccia principale della classe, utilizzata dagli sviluppatori di pagine Web; e
  2. Un'interfaccia "nascosta" utilizzata dal presentatore che sviluppo per gestire la logica del controllo

Segue un semplice esempio. È un controllo casella combinata che elenca i clienti. In questo esempio, lo sviluppatore di pagine Web non è interessato a popolare l'elenco; invece, vogliono solo essere in grado di selezionare un cliente dal GUID o di ottenere il GUID del cliente selezionato. Un relatore popolerà la casella al caricamento della prima pagina e questo relatore è incapsulato dal controllo.

public sealed class CustomerComboBox : ComboBox, ICustomerComboBox {
    private readonly CustomerComboBoxPresenter presenter;

    public CustomerComboBox() {
        presenter = new CustomerComboBoxPresenter(this);
    }

    protected override void OnLoad() {
        if (!Page.IsPostBack) presenter.HandleFirstLoad();
    }

    // Primary interface used by web page developers
    public Guid ClientId {
        get { return new Guid(SelectedItem.Value); }
        set { SelectedItem.Value = value.ToString(); }
    }

    // "Hidden" interface used by presenter
    IEnumerable<CustomerDto> ICustomerComboBox.DataSource { set; }
}

Il relatore popola l'origine dati e lo sviluppatore di pagine Web non deve mai essere consapevole della sua esistenza.

Ma non è una palla di cannone d'argento

Non consiglierei di utilizzare sempre implementazioni di interfaccia esplicite. Questi sono solo due esempi in cui potrebbero essere utili.


19

Oltre agli altri motivi già indicati, questa è la situazione in cui una classe sta implementando due diverse interfacce che hanno una proprietà / metodo con lo stesso nome e firma.

/// <summary>
/// This is a Book
/// </summary>
interface IBook
{
    string Title { get; }
    string ISBN { get; }
}

/// <summary>
/// This is a Person
/// </summary>
interface IPerson
{
    string Title { get; }
    string Forename { get; }
    string Surname { get; }
}

/// <summary>
/// This is some freaky book-person.
/// </summary>
class Class1 : IBook, IPerson
{
    /// <summary>
    /// This method is shared by both Book and Person
    /// </summary>
    public string Title
    {
        get
        {
            string personTitle = "Mr";
            string bookTitle = "The Hitchhikers Guide to the Galaxy";

            // What do we do here?
            return null;
        }
    }

    #region IPerson Members

    public string Forename
    {
        get { return "Lee"; }
    }

    public string Surname
    {
        get { return "Oades"; }
    }

    #endregion

    #region IBook Members

    public string ISBN
    {
        get { return "1-904048-46-3"; }
    }

    #endregion
}

Questo codice viene compilato ed eseguito correttamente, ma la proprietà Title è condivisa.

Chiaramente, vorremmo che il valore di Title restituito dipendesse dal fatto che stessimo trattando Class1 come un libro o una persona. Questo è quando possiamo usare l'interfaccia esplicita.

string IBook.Title
{
    get
    {
        return "The Hitchhikers Guide to the Galaxy";
    }
}

string IPerson.Title
{
    get
    {
        return "Mr";
    }
}

public string Title
{
    get { return "Still shared"; }
}

Si noti che le definizioni dell'interfaccia esplicita vengono dedotte come pubbliche, pertanto non è possibile dichiararle esplicitamente pubbliche (o altrimenti).

Si noti inoltre che è ancora possibile avere una versione "condivisa" (come mostrato sopra), ma mentre ciò è possibile, l'esistenza di tale proprietà è discutibile. Forse potrebbe essere usato come implementazione predefinita di Title - in modo che il codice esistente non debba essere modificato per trasmettere Class1 a IBook o IPerson.

Se non si definisce il titolo "condiviso" (implicito), i consumatori di Classe 1 devono esplicitamente trasmettere prima istanze di Classe 1 a IBook o IPerson, altrimenti il ​​codice non verrà compilato.


16

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:

  1. 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.
  2. (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à).

8

Se si implementa in modo esplicito, sarà possibile fare riferimento ai membri dell'interfaccia solo tramite un riferimento del tipo di interfaccia. Un riferimento che è il tipo della classe di implementazione non esporrà quei membri dell'interfaccia.

Se la tua classe di implementazione non è pubblica, ad eccezione del metodo utilizzato per creare la classe (che potrebbe essere un contenitore factory o IoC ) e ad eccezione dei metodi di interfaccia (ovviamente), non vedo alcun vantaggio nell'implementazione esplicita interfacce.

In caso contrario, l'implementazione esplicita delle interfacce garantisce che i riferimenti alla propria classe di implementazione concreta non vengano utilizzati, consentendo di modificare tale implementazione in un secondo momento. "Sicuro", suppongo, è il "vantaggio". Un'implementazione ben ponderata può raggiungere questo obiettivo senza un'implementazione esplicita.

Lo svantaggio, a mio avviso, è che ti troverai a lanciare tipi da / verso l'interfaccia nel codice di implementazione che ha accesso a membri non pubblici.

Come molte altre cose, il vantaggio è lo svantaggio (e viceversa). L'implementazione esplicita delle interfacce assicurerà che il codice di implementazione della tua classe concreta non sia esposto.


1
Bella risposta, Bill. Le altre risposte sono state fantastiche, ma hai fornito alcuni punti di vista oggettivi aggiuntivi (oltre alle tue opinioni) che mi hanno facilitato la comprensione. Come la maggior parte delle cose ci sono pro e contro con implementazioni implicite o esplicite, quindi devi solo usare quello migliore per il tuo particolare scenario o caso d'uso. Direi che coloro che cercano di capire meglio trarranno vantaggio dalla lettura della tua risposta.
Daniel Eagle,

6

Un'implementazione implicita dell'interfaccia è quella in cui hai un metodo con la stessa firma dell'interfaccia.

Un'implementazione esplicita dell'interfaccia è dove dichiari esplicitamente a quale interfaccia appartiene il metodo.

interface I1
{
    void implicitExample();
}

interface I2
{
    void explicitExample();
}


class C : I1, I2
{
    void implicitExample()
    {
        Console.WriteLine("I1.implicitExample()");
    }


    void I2.explicitExample()
    {
        Console.WriteLine("I2.explicitExample()");
    }
}

MSDN: implementazioni di interfaccia implicite ed esplicite


6

Ogni membro della classe che implementa un'interfaccia esporta una dichiarazione che è semanticamente simile al modo in cui sono scritte le dichiarazioni dell'interfaccia VB.NET, ad es.

Public Overridable Function Foo() As Integer Implements IFoo.Foo

Sebbene il nome del membro della classe corrisponderà spesso a quello del membro dell'interfaccia e il membro della classe sarà spesso pubblico, nessuna di queste cose è richiesta. Si può anche dichiarare:

Protected Overridable Function IFoo_Foo() As Integer Implements IFoo.Foo

Nel qual caso la classe e i suoi derivati ​​sarebbero autorizzati ad accedere a un membro della classe usando il nome IFoo_Foo, ma il mondo esterno sarebbe in grado di accedere a quel particolare membro solo lanciando IFoo. Tale approccio è spesso valido nei casi in cui un metodo di interfaccia avrà un comportamento specifico su tutte le implementazioni, ma un comportamento utile solo su alcuni [ad esempio IList<T>.Add, è necessario lanciare il comportamento specificato per il metodo di una raccolta di sola lettura NotSupportedException]. Sfortunatamente, l'unico modo corretto per implementare l'interfaccia in C # è:

int IFoo.Foo() { return IFoo_Foo(); }
protected virtual int IFoo_Foo() { ... real code goes here ... }

Non così carino.


2

Un uso importante dell'implementazione esplicita dell'interfaccia è quando è necessario implementare interfacce con visibilità mista .

Il problema e la soluzione sono ben spiegati nell'articolo Interfaccia interna C # .

Ad esempio, se si desidera proteggere la perdita di oggetti tra i livelli dell'applicazione, questa tecnica consente di specificare una diversa visibilità dei membri che potrebbero causare la perdita.


2

Le risposte precedenti spiegano perché l'implementazione esplicita di un'interfaccia in C # può essere preferibile (per ragioni principalmente formali). Tuttavia, esiste una situazione in cui l'implementazione esplicita è obbligatoria : al fine di evitare la perdita dell'incapsulamento quando l'interfaccia non è public, ma lo è la classe di implementazione public.

// Given:
internal interface I { void M(); }

// Then explicit implementation correctly observes encapsulation of I:
// Both ((I)CExplicit).M and CExplicit.M are accessible only internally.
public class CExplicit: I { void I.M() { } }

// However, implicit implementation breaks encapsulation of I, because
// ((I)CImplicit).M is only accessible internally, while CImplicit.M is accessible publicly.
public class CImplicit: I { public void M() { } }

La perdita di cui sopra è inevitabile perché, secondo la specifica C # , "Tutti i membri dell'interfaccia hanno implicitamente accesso al pubblico". Di conseguenza, anche le implementazioni implicite devono consentire l' publicaccesso, anche se l'interfaccia stessa è es internal.

L'implementazione implicita dell'interfaccia in C # è una grande comodità. In pratica, molti programmatori lo usano sempre / ovunque senza ulteriori considerazioni. Questo porta a superfici di tipo disordinato nella migliore delle ipotesi e incapsulamento trapelato nella peggiore. Altre lingue, come F #, non lo consentono nemmeno .

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.