C# : Implementazione delle interfacce e la derivazione

Supponiamo di avere una semplice interfaccia così definita :

interface IMyInterface
{
    void MyMethod();
}

e di definire una classe che la implementa :

class BaseClass : IMyInterface
{
    public void MyMethod()
    {
        Console.WriteLine("BaseClass.MyMethod()");
    }
}

Supponiamo di voler derivare da quest’ultima una nuova classe per poter eseguire l’override del metodo MyMethod(). Ebbene un’operazione di questo tipo non sarà ovviamente possibile, considerando che ogni metodo di un’interfaccia viene marcata come virtual ma soprattutto come sealed dal CLR.

Il fatto che sia virtual, permette alla classe che implementa l’interfaccia di implementarne il metodo mentre il fatto che sia sealed non ne permette l’override nella classe derivata.

A questo punto le possibili soluzioni sono due :

  • nella BaseClass, marchiamo il metodo come virtual in modo che la classe derivata potrà farne l’override e non avrà bisogno di implementare l’interfaccia. Con questa soluzione perdiamo però lo sviluppo e le invocazioni per interfacce;
  • facciamo in modo che anche la classe derivata implementi l’interfaccia ma a quel punto sarà necessario utilizzare l’operatore new nella dichiarazione del metodo che altrimenti nasconderà quello della classe base. Nella classe base non sarà necessario utilizzare virtual;

Con la prima soluzione abbiamo :

class BaseClass : IMyInterface
{
    public virtual void MyMethod()
    {
        Console.WriteLine("BaseClass.MyMethod()");
    }
}

class DerivedClass : BaseClass
{
    public override void MyMethod()
    {
        Console.WriteLine("DerivedClass.MyMethod()");
    }
}

mentre con la seconda :

class BaseClass : IMyInterface
{
    public void MyMethod()
    {
        Console.WriteLine("BaseClass.MyMethod()");
    }
}

class DerivedClass : BaseClass, IMyInterface
{
    new public void MyMethod()
    {
        Console.WriteLine("DerivedClass.MyMethod()");
    }
}

A questo punto consideriamo il seguente Main di esempio :

static void Main(string[] args)
{
BaseClass bClass = new BaseClass();
bClass.MyMethod();

bClass = new DerivedClass();
bClass.MyMethod();
}

il cui output sarà il seguente rispettivamente per la prima e per la seconda soluzione :

1376.interface2_7115F8C5

0743.interface3_16334332

Nel primo caso, il concetto di interfaccia è decaduto passando dalla classe base a quella derivata e quindi invocando la seconda volta bClass.MyMethod() viene giustamente invocata l’implementazione della DerivedClass (in quanto bClass punta ad un’istanza di tale classe).

Nel secondo caso, viene invece invocato sempre il metodo della classe base, in quanto nellaDerivedClass, il metodo MyMethod() non è un’override del corrispondente metodo nella classe base ma una nuova versione (operatore new) nell’implentazione dell’interfaccia. Per ovviare a questo comportamento è necessario esplicitare il casting all’interfaccia IMyInterfacenella seconda invocazione nel modo seguente :

bClass = new DerivedClass();
((IMyInterface)bClass).MyMethod();

per cui l’output sarà il seguente :

3056.interface4_5CB0333A

Ovviamente, se avessimo utilizzato direttamente un riferimento di tipo DerivedClass per puntare ad un’istanza della stessa DerivedClass, questo cast esplicito non si sarebbe reso necessario.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s