2012-05-19 14 views
5

OK, ecco cosa mi piacerebbe fare.Riferimento automatico nelle interfacce

Class Container<T> 
{ 
    T contained; 
    public void ContainObject(T obj) 
    { 
     contained = obj; 
     if(/*Magical Code That Detects If T Implemtns IContainableObject*/) 
     { 
      IContainableObect c = (IContainableObject)obj; 
      c.NotifyContained(self); 
     } 
    } 
} 

interface IContainableObject 
{ 
    public void NotifyContained(Container<REPLACE_THIS>);//This line is important, see below after reading code. 
} 



Class ImplementingType : IContaiableObject 
{ 
    public Container<ImplementingType> MyContainer; 
    public void NotifyContained(Container<ImplmentingType> c) 
    { 
     MyContainer = c; 
    } 
} 




Class Main 
{ 
    public static void Main(args) 
    { 
     ImplementingType iObj = new ImplementingType(); 
     Container<ImplementingType> container = new Container(); 
     container.ContainObject(iObj); 
     //iObj.MyContainer should now be pointing to container. 
    } 
} 

In sostanza, per riassumere l'esempio di cui sopra, ho un tipo wrapper generico di tipo T. vorrei che tipo di involucro a comunicare tutto suo contento che sta per essere contenuta (con una copia della sua auto !) SE l'oggetto contenuto implementa un'interfaccia specifica (questo bit so come fare)

Ma diventa complicato! Perché? Bene perché il contenitore generico deve avere un tipo.

Ricordare quella linea importante?

Se REPLACE_THIS è IContainableObject, allora tutti gli implementatori dell'interfaccia devono utilizzare IContainerObject, non il nome della classe che implementa nel loro metodo NotifyContained.

Utilizzare ImplementingType poiché il tipo di contenitore all'interno dell'interfaccia è ancora peggiore, per ovvi motivi!

Quindi la mia domanda è: cosa devo fare per far sì che REPLACE_THIS rappresenti la classe dell'oggetto che implementa l'interfaccia?

risposta

4
class Container<T> 
{ 
    T contained; 
    public void ContainObject(T obj) 
    { 
     contained = obj; 
     var containable = obj as IContainableObject<T>; 
     if(containable != null) 
     { 
      containable.NotifyContained(this); 
     } 
    } 
} 

interface IContainableObject<T> 
{ 
    void NotifyContained(Container<T> c); 
} 

class ImplementingType : IContainableObject<ImplementingType> 
{ 
    public Container<ImplementingType> MyContainer; 
    public void NotifyContained(Container<ImplementingType> c) 
    { 
     MyContainer = c; 
    } 
} 

EDIT: aggiungere la versione con il vincolo generico

interface IContainer<T> 
{ 
    void ContainObject(T obj); 
} 

class Container<T> : IContainer<T> where T : IContainableObject<T> 
{ 
    T contained; 

    public void ContainObject(T obj) 
    { 
     contained = obj; 
     contained.NotifyContained(this); 
    } 
} 

interface IContainableObject<T> 
{ 
    void NotifyContained(IContainer<T> c); 
} 

class ImplementingType : IContainableObject<ImplementingType> 
{ 
    public IContainer<ImplementingType> MyContainer; 

    public void NotifyContained(IContainer<ImplementingType> c) 
    { 
     Debug.WriteLine("notify contained"); 
     MyContainer = c; 
    } 
} 
+0

Grazie molto! Funziona come un fascino :) –

+1

È possibile evitare il casting se si dichiara un vincolo generico per T. –

+0

Oops Ho appena notato un errore di battitura nel mio codice di esempio dopo aver notato di aver creato un'interfaccia vuota per IContainerObject - I Accidentally typed IContainer not IContainable. Questo significa che la tua interfaccia IContainer può essere semplicemente rimossa? –

1

Forse tu lo sai già, ma se solo IContainableObjects sono ammessi come T si può dichiarare la classe come questo

class Container<T> 
    where T : IContainableObject 
{ 
    public void ContainObject(T obj) 
    { 
     // Here you know that obj does always implement IContainableObject. 
     obj.NotifyContained(this); 
    } 

    ... 
} 
+0

Soluzione interessante! IContainableObject è un'interfaccia opzionale - Solo per chi lo desidera, quindi questa non è un'opzione praticabile per me, ma in qualsiasi altro caso, sembra che funzionerebbe :) –

Problemi correlati