In .NET, l’implementazione di una interfaccia può essere implicita o esplicita. E’ implicita quando i metodi dell’interfaccia sono definiti come normali metodi della classe e marcati come pubblici. I’implementazione è invece esplicita quando il metodo nella classe è associato direttamente all’interfaccia. In questo caso il metodo non è pubblico e non è visibile nell’interfaccia (anche via IntelliSense) della classe.
Il punto è: è preferibile che l’implementazione dell’interfaccia sia implicita o esplicita. Cosa ci si guadagna e perde in ciascun caso?
L’implementazione implicita è probabilmente l’approccio più comune. Ogni metodo dell’interfaccia diventa un metodo pubblico della classe e in quanto tale diventa parte dell’interfaccia di programmazione della classe stessa. Ecco un esempio:
interface ISomething
{
void Proceed();
}
public class Demo: ISomething
{
public void Proceed()
{ ... }
}
Questo approccio funziona nella maggior parte dei casi, ma non sempre. Immaginiamo uno scenario in cui una classe implementi due (o più) interfacce e, soprattutto, immaginiamo che entrambe le interfacce abbiano un metodo in comune—stesso nome e stesso insieme di parametri. Ecco un esempio:
interface IThis
{
void Proceed();
}
interface IThat
{
void Proceed();
}
public class Demo: IThis, IThat
{
// ???
}
Come deve essere costruito il codice della classe? Una possibile soluzione è aggiungere un metodo pubblico che possa servire entrambe le interfacce:
public class Demo : IThis, IThat
{
public void Proceed()
{
Console.WriteLine("Proceed");
}
}
In questo modo è possibile invocare il metodo su istanze di tipo Demo, IThis e IThat. Tutto bene? Mica tanto. Cosa accade se, a dispetto dello stesso nome e della stessa firma, in realtà il metodo Proceed di IThis è logicamente diverso dal metodo Proceed di IThat?
In questo caso è necessario aggiungere una seconda implementazione di Proceed. Tuttavia entrambe devono essere agganciate alle rispettive interfacce per evitare conflitti e confusione. Ne consegue che l’implemetazione di almeno una delle interfacce deve essere esplicita.
public class Demo : IThis, IThat
{
void IThis.Proceed()
{
Console.WriteLine("IThis.Process");
}
public void Proceed()
{
Console.WriteLine("IThat.Process");
}
}
L’implementazione è esplicita se il nome del metodo ha il nome dell’interfaccia come prefisso (diciamo IThis). Ciò significa che per invocare quel particolare pezzo di codice sarà necessario ricorrere ad una variabile di tipo IThis. Il seguente codice invoca il metodo IThis.Proceed.
var c = new Demo() as IThis;
c.Proceed();
Il seguente codice invece invoca il metodo Proceed.
var c = new Demo();
c.Proceed();
A parte la situazione appena illustrata, quando l’interfaccia esplicita è preferibile? A mio modo di vedere è fondamentalmente una questione di preferenza. L’interfaccia implicita (se applicabile) è più semplice e crea meno problemi . Per esempio, non c’è bisogno di fare cast per invocare un metodo. E’ da notare il fatto che il cast può diventare un fatto di performance se stiamo parlando di un’interfaccia che estende un value type. In questo caso, si obbliga la CLR ad eseguire un’operazione di boxing per poter rendere il value type tramite un’interfaccia.
L’interfaccia esplicita è più pulita nel senso che ciascun metodo appartiene al suo specifico scenario—quello rappresentato dall’interfaccia. Come fare, però, a rendere pubblico il metodo senza obbligare il programmatore al cast? E’ sufficiente aggiungere un altro metodo magari con un nome diverso che semplicemente invoca il metodo dell’interfaccia. Ecco come:
public class Demo : IThis
{
void IThis.Proceed()
{
Console.WriteLine("IThis.Process");
}
public void GoAhead()
{
var x = (IThis) this;
x.Proceed();
}
}
Ovviamente un cast è comunque necessario per poter invocare il metodo dell’interfaccia, ma almeno è nascosto nel framework e non richiesto al programmatore che usa la classe Demo.


Commenti