Ok, questo deriva da alcune discussioni in corso here.Implementare due volte un'interfaccia esplicita per ottenere un comportamento "virtuale" come un brutto attacco?
Immaginate il seguente scenario. Società Alpha pubblica biblioteca Charlie
che espone, tra gli altri, un tipo Charlie.Bar
che explicilty implementa l'interfaccia IFooable
:
public interface IFooable
{
void Foo();
}
namespace Charlie
{
public clas Bar: IFooable
{
void IFooable.Foo() {...}
....
}
}
Ora accade che società Beta è sottoclassi Charlie.Bar
nella sua libreria Tango
per alcuni molto particolari funzionalità in cui l'implementazione esplicita di IFooable.Foo
non lo taglia. Beta deve "ignorare" l'implementazione dell'interfaccia e ottenere un comportamento virtuale apparentemente equivalente; Le chiamate a IFooable.Foo()
dovrebbero essere risolte correttamente con il tipo di runtime dell'oggetto. Si noti che la società Alpha modificare l'implementazione di Charlie.Bar
non è un'opzione valida.
Quindi, come può essere fatto? I metodi di interfaccia esplicita sono contrassegnati in CIL come virtual
e final
quindi non è possibile sovrascriverli. Beta si avvicinò con questo "hack":
using Charlie;
namespace Tango
{
class Blah: Bar, IFooable
{
void IFooable.Foo() { //Bar specific implementation }
}
}
nota l'attuazione di IFooable
nuovo in Blah
anche se è ridondante. Con questo codice, è effettivamente ottenere lo stesso comportamento di un metodo virtuale al momento della chiamata IFooable.Foo()
:
IFooable fooBar = new Bar();
IFooable fooBlah = new Blah();
fooBlah.Foo() // Blah's implementation is called.
fooBar.Foo() // Bar's implementation is called.
È questo un brutto hack? (L'ho visto fatto in scenari similmente giustificati). Quali sono le alternative se presenti?
'IFooable' non è ridondante qui. Questa è chiamata re-implementazione dell'interfaccia. La mia risposta [qui] (http://stackoverflow.com/a/25008171/517852) ha alcune spiegazioni su questa funzione. Uno svantaggio è che con la re-implementazione dell'interfaccia non si ha la possibilità di chiamare l'implementazione di base. –
'' Blah' * necessita * di essere un sottotipo di 'Bar'? In caso contrario, è possibile utilizzare la composizione: memorizzare un riferimento a una 'Barra' nella classe' Blah' e inoltrare tutte le chiamate pertinenti a tale. – Medo42
Mikez ha ragione. Non è ridondante o hack. È una [funzionalità] (http://msdn.microsoft.com/en-us/library/aa664594%28v=vs.71%29.aspx). –