2012-12-19 16 views
11

Prendete questo esempio:In C#, perché le implementazioni di interfaccia devono implementare esplicitamente un'altra versione di un metodo?

public interface IFoo 
{ 
    IFoo Bar(); 
} 

public class Foo : IFoo 
{ 
    public Foo Bar() 
    { 
     //... 
    } 

    IFoo IFoo.Bar() { return Bar(); } //Why is this necessary? 
} 

Perché l'implicita implementazione di IFoo Bar() necessaria anche se Foo converte in IFoo senza un cast?

+0

Perché stai facendo questo? Stai effettivamente legando gli utenti di "Foo" all'implementazione concreta, rendendo difficile il mocking per i test unitari e, in generale, aumentando l'accoppiamento nella tua applicazione ... –

+0

I due approcci sono praticamente mutuamente esclusivi. Entrambi funzionano ma hanno scopi diversi. Non useresti entrambi gli approcci per la stessa interfaccia nella stessa classe concreta (almeno non che io possa pensare) – dkackman

+0

@SteveCzetty Quindi la domanda dell'OP; dove è necessario implementare esplicitamente l'interfaccia. –

risposta

4

È possibile risolvere in questo modo (un po 'brutto, ma si prende cura della tipizzazione forte):

public interface IFoo<T> where T : IFoo<T> 
{ 
    T Bar(); 
} 

public class Foo : IFoo<Foo> 
{ 
    public Foo Bar() 
    { 
     //... 
    } 
} 
+1

Большое спасибо, תודה רבה! – Matt

+0

Questo non viene compilato poiché non esiste un'interfaccia 'IFoo' non generica. –

+0

Hai ragione, ho modificato il codice. –

3

Perché non sempre si desidera che il metodo che implementa l'interfaccia si comporti allo stesso modo di un'altra versione del metodo con la stessa firma.

Si consiglia inoltre a una classe di implementare un metodo per un'interfaccia, ma affinché tale metodo non sia accessibile da un'istanza della classe stessa.

5

Microsoft ha uno detailed write up sull'argomento ma si riduce all'implementazione di più interfacce/classi che hanno lo stesso metodo in esse. Implicito non funziona più in quel contesto.

class Test 
{ 
    static void Main() 
    { 
     SampleClass sc = new SampleClass(); 
     IControl ctrl = (IControl)sc; 
     ISurface srfc = (ISurface)sc; 

     // The following lines all call the same method. 
     sc.Paint(); 
     ctrl.Paint(); 
     srfc.Paint(); 
    } 
} 


interface IControl 
{ 
    void Paint(); 
} 
interface ISurface 
{ 
    void Paint(); 
} 
class SampleClass : IControl, ISurface 
{ 
    // Both ISurface.Paint and IControl.Paint call this method. 
    public void Paint() 
    { 
     Console.WriteLine("Paint method in SampleClass"); 
    } 
} 

// Output: 
// Paint method in SampleClass 
// Paint method in SampleClass 
// Paint method in SampleClass 

Se dovessimo prendere l'approccio esplicito, finiamo con questo.

Tutto si riduce alla fornitura di unicità quando i tipi implementati si scontrano. Nel tuo esempio, FooèIFoo.

+0

Sì, ma qui c'è solo un'interfaccia. – Matt

+0

Questo non risponde alla domanda sul tipo di reso. –

+0

@Matt Regola leggermente la verbosità, per notare che una singola interfaccia è in gioco ma la classe implementa anche quella firma del metodo. –

5

E' necessario in questo caso perché C# non supporta tipo di ritorno covarianza per le interfacce, così la funzione

public Foo Bar() 
{ 
    //... 
} 

non soddisfa l'interfaccia IFoo in quanto il tipo di ritorno del metodo Bar è diverso.

Poiché si desidera implementare anche l'interfaccia, l'unica possibilità è di farlo in modo esplicito poiché si dispone già di un metodo Bar() definito sulla classe.

+0

Sì, ma ** perché ** C# non lo consente? –

+2

@IlyaKogan - Non so perché C# non supporta la covarianza di tipo restituito - dovresti chiedere ai progettisti. C# generalmente preferisce che le cose siano rese esplicite, quindi è probabilmente per impedire che le interfacce vengano accidentalmente implementate implicitamente. – Lee

+1

@IlyaKogan Questo riporta a tutte le domande su _why_ in merito all'implementazione; perché hanno scelto di –

0

Si consiglia di mantenere l'implementazione implicita come protetta anziché pubblica.

public class Foo : IFoo 
{ 
    **protected virtual** Foo Bar() 
    { 
     //... 
    } 

    IFoo IFoo.Bar() { return Bar(); } 
} 

c'è una risposta piuttosto esteso del perché/quando usare esplicita implementazione in questa discussione:

implicit vs explicit interface implementation

Una buona ragione per utilizzare l'implementazione esplicita è che si può facilmente utilizzare l'iniezione di dipendenza avere un accoppiamento più libero quando usi la tua classe Foo.

Problemi correlati