Non ho mai sentito parlare su UgiDotNet di markers interfaces, non so se dipenda dal fatto che vi sono iscritto da relativamente poco tempo, o se proprio l'argomento non è mai stato toccato. Stasera, durante una sessione di sviluppo di IMHO 2.0 mi sono trovato di fronte all'esigenza di usarle per risolvere con eleganza un problema che mi si è presentato, perciò ho deciso di proporvi in questo breve post qualche spezzone di codice per illustrarvene l'utilità.

Innanzitutto vediamo di spiegare in due parole che cosa intendo quando parlo di markers interfaces. Chiunque abbia un po' di dimestichezza con la programmazione ad oggetti sa bene cosa sia un'interfaccia. Tipicamente nei libri viene definita come un contratto che stabilisce quali metodi dovranno contenere le classi che la implementano. In C#, e genericamente nel framework .NET una classe può implementare più di una interfaccia e questo permette di realizzare il polimorfismo delle classi. Non voglio ora dilungarmi in esempi in merito, ma darò per scontato che l'argomento sia ormai ben conosciuto. Ora vi pongo una domanda: cosa succede se dichiaro una interfaccia senza alcun metodo? Semplicemente nulla. Il compilatore non solleverà nemmeno uno warning per farci notare la bizzarria. Di primo acchito si potrebbe dire che una interfaccia senza metodi esposti non serve veramente a nulla, se non che, andando a spulciare l'SDK del framework si scoprirà che di interfacce di questo tipo ve ne sono e anche parecchie. Provate ad esempio a vedere la IReadOnlySessionState. Tale interfaccia è definita una marker interface e verrà implementata dalla classe che il compilatore crea quando compila una pagina aspx, se nella direttiva Page viene specificato EnableSessionState="ReadOnly". Questo è un modo rapido ed elegante di trasformare una proprietà in un comportamento. Usando un marker, nel codice si potrà fare uso dell'operatore "is" per verificare se la classe implementa l'interfaccia ed agire di conseguanza.

Ma visto che un esempio vale mille parole, eccovi come ho impiegato io una marker interface. Uno dei problemi tipici della programmazione ad oggetti è il mapping tra il mondo relazionale e quello oop. In IMHO 2.0 ho deciso di non adottare un framework di persistenza che si occupasse anche di questa problematica perchè in realtà non posso direche ne esistano di veramente maturi e per una questione di licenze nemmeno di praticamente usabili nel mio caso. Perciò mi sono "arrangiato" implementando un po' di patterns. Innanzitutto ho creato una Factory cui passo il tipo di oggetto da create è il DataReader da cui attingere:

public static ImhoObject Create(
    Type type,
    IDataReader reader)
{
    
if (type==typeof(User))
        
return CreateUser(reader);
    
else if (type==typeof(Role))
        
return CreateRole(reader);

    
throw new ApplicationException("Unknown type");
}

private static User CreateUser( IDataReader reader )
{
    
if ( reader.Read() )
    {
        User user = newUser();
 
        // omissis: popolo l'oggetto con il reader...

        
return user;
    }

    
return new UnknownUser();
}
 
Questo metodo è stato creato per poter estrarre da un reader un singolo oggetto. In questo modo è possibile riutilizzarlo sia nel caso di una lettura singola, sia nel caso di un reader contenente molti oggetti. Analizzando per bene il codice si vede anche che ho implementato il pattern SpeciaCase infatti nel caso in cui il reader non contenga alcun oggetto restituisco un'istanza di UnknownUser, una classe che eredita da User e che rappresenta il caso in cui un utente non esiste. A questo punto mi sono trovato nella necessità di creare un metodo che dato un reader lo scandisca da cima a fondo e restituisca un array di oggetti estratti da esso. Il problema risiedeva nel fatto che creando tale metodo, in modo che facesse uso al suo interno del metodo Create(), mi trovavo nella necessità di testare l'oggetto restituito e nel caso in cui esso fosse UnknownUser uscire dal loop. Però così facendo mi sarei anche trovato nella necessità di creare un metodo ad-hoc per ogni classe di oggetto, User, Role, Weblog, e cosi' via. Ho così immaginato che per ognuno di essi sarebbe esistito l'Unknown e preso atto del fatto che avevo predisposto una radice della gerarchia di oggetti in ImhoObject, ho deciso di marcare le classi di tipo Unknown con una interfaccia INonExistentImhoObject in questo modo:
 
[Serializable]
public class UnknownUser : 
    User, INotExistentImhoObject
{
    
public UnknownUser()
    {}
}
 
Così facendo mi sono finalmente potuto creare un metodo completamente generico che sfruttasse l'interfaccia marker per gestire il raggiungimento della fine del reader:
 
public static Array CreateArray( 
    Type type, 
    IDataReader reader )
{
    ArrayList list = 
new ArrayList();
    ImhoObject item;

    
while( !( ( item = Create( type, reader ) ) 
        
is INotExistentImhoObject ) )
        list.Add( item );

    
return list.ToArray( type ) as Array;
}
 
Et-voilà il gioco è fatto. Il metodo è del tutto generico tanto che basta passare il tipo di oggetto e il reader e puntualmente ritornerà un array contenente gli oggetti richiesti. Solo un rilievo. La condzione del ciclo while è scritta come piace a me, in puro stile "C", so che per molti risulterà antipatica, perchè soffre un po' di scarsa leggibilità, ma volete mettere: due righe e nemmeno una parentesi graffa!

powered by IMHO 1.2


per leggere il post originale o inviare un commento visita il seguente indirizzo: Marker Interfaces