DI: gestione della vita di oggetti idisposabili

Quindi sto lavorando al mio contenitore DI / IoC OpenNETCF.IoC e ho una (ragionevole) richiesta di funzionalità per aggiungere una qualche forma di gestione del ciclo di vita per gli elementi IDisposable nelle raccolte contenitore.

Il mio pensiero corrente è che, dal momento che non posso interrogare un object per vedere se è stato eliminato, e non riesco a ottenere un evento per quando è stato eliminato, devo creare qualche forma di wrapper per gli oggetti che uno sviluppatore vuole la struttura da gestire.

In questo momento gli oggetti possono essere aggiunti con AddNew (per semplicità supponiamo che ci sia solo un sovraccarico e non ci sia Aggiungi):

public TTypeToBuild AddNew() { ... } 

Quello che sto considerando è l’aggiunta di un nuovo metodo (ben raggruppato, ma ottieni l’immagine):

 public DisposableWrappedObject AddNewDisposable() where TTypeToBuild : class, IDisposable { ... } 

Dove il DisposableWrappedObject si presenta così:

 public class DisposableWrappedObject where T : class, IDisposable { public bool Disposed { get; private set; } public T Instance { get; private set; } internal event EventHandler<GenericEventArgs> Disposing; internal DisposableWrappedObject(T disposableObject) { if (disposableObject == null) throw new ArgumentNullException(); Instance = disposableObject; } ~DisposableWrappedObject() { Dispose(false); } public void Dispose() { Dispose(true); } protected virtual void Dispose(bool disposing) { lock(this) { if(Disposed) return; EventHandler<GenericEventArgs> handler = Disposing; if(handler != null) { Disposing(this, new GenericEventArgs(Instance)); } Instance.Dispose(); Disposed = true; } } } 

Ora, quando un object viene aggiunto al contenitore tramite AddNewDIsposable, viene anche aggiunto un eventhandler in modo che quando viene eliminato (tramite il wrapper) il framework lo rimuova dalla raccolta sottostante.

In realtà l’ho implementato e sto superando i test unitari, ma sto cercando opinioni su dove questo potrebbe essere rotto, o su come potrebbe essere reso più “amichevole” allo sviluppatore che consuma.

MODIFICA 1

Poiché c’era una domanda su come viene usato l’evento Disposing, ecco un codice (tagliato per quello che è importante):

 private object AddNew(Type typeToBuild, string id, bool wrapDisposables) { .... object instance = ObjectFactory.CreateObject(typeToBuild, m_root); if ((wrapDisposables) && (instance is IDisposable)) { DisposableWrappedObject dispInstance = new DisposableWrappedObject(instance as IDisposable); dispInstance.Disposing += new EventHandler<GenericEventArgs>(DisposableItemHandler); Add(dispInstance as TItem, id, expectNullId); instance = dispInstance; } .... return instance; } private void DisposableItemHandler(object sender, GenericEventArgs e) { var key = m_items.FirstOrDefault(i => i.Value == sender).Key; if(key == null) return; m_items.Remove(key); } 

Forse mi manca qualcosa, ma perché aggiungere nuovi metodi all’API? Quando un object viene aggiunto al contenitore, puoi eseguire l’as-cast per verificare se è idisposto e gestirlo in modo appropriato in caso affermativo.

Mi sto anche chiedendo se hai bisogno del distruttore. Presumendo che il contenitore sia IDisposable (come Unity’s), potresti semplicemente implementare il Basic Dispose Pattern e risparmiare un sacco di overhead di GC.

Alcune domande che potrebbero essere applicabili:

  • Come si riconciliano IDisposable e IoC?
  • L’inversione di controllo e RAII possono giocare insieme?