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.DI: gestione della vita di oggetti idisposti
Il mio pensiero corrente è che, dal momento che non posso interrogare un oggetto 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 che la struttura sia gestita.
In questo momento gli oggetti possono essere aggiunti con AddNew (per semplicità si suppone c'è solo un sovraccarico e non c'è Add):
public TTypeToBuild AddNew<TTypeToBuild>() { ... }
Quello che sto considerando è l'aggiunta di un nuovo metodo (bene gruppo di loro, ma si ottiene l'immagine):
public DisposableWrappedObject<IDisposable> AddNewDisposable<TTypeToBuild>()
where TTypeToBuild : class, IDisposable
{
...
}
Qualora il DisposableWrappedObject assomiglia a questo:
public class DisposableWrappedObject<T>
where T : class, IDisposable
{
public bool Disposed { get; private set; }
public T Instance { get; private set; }
internal event EventHandler<GenericEventArgs<IDisposable>> 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<IDisposable>> handler = Disposing;
if(handler != null)
{
Disposing(this, new GenericEventArgs<IDisposable>(Instance));
}
Instance.Dispose();
Disposed = true;
}
}
}
Ora, quando un oggetto 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à ho implementato questo e sta 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.
EDIT 1
Poiché non vi era una domanda su come viene utilizzato l'evento Smaltimento, ecco qualche codice (tagliato a ciò che è importante):
private object AddNew(Type typeToBuild, string id, bool wrapDisposables)
{
....
object instance = ObjectFactory.CreateObject(typeToBuild, m_root);
if ((wrapDisposables) && (instance is IDisposable))
{
DisposableWrappedObject<IDisposable> dispInstance = new
DisposableWrappedObject<IDisposable>(instance as IDisposable);
dispInstance.Disposing += new
EventHandler<GenericEventArgs<IDisposable>>(DisposableItemHandler);
Add(dispInstance as TItem, id, expectNullId);
instance = dispInstance;
}
....
return instance;
}
private void DisposableItemHandler(object sender, GenericEventArgs<IDisposable> e)
{
var key = m_items.FirstOrDefault(i => i.Value == sender).Key;
if(key == null) return;
m_items.Remove(key);
}
Possiamo ottenere una descrizione più completa della funzione specifica che si aggiunge? Quali sono i casi d'uso per cui la gente vuole questo, è il gestore di eventi per te come il (framework IoC) o l'utente finale? Ecc .. – Quibblesome
Il caso d'uso è di aggiungere la gestione del ciclo di vita automatizzata. Se si aggiunge un elemento IDisposable a una raccolta e successivamente si chiama Dispose, esso non verrà mai ripulito in quanto il contenitore contiene una radice per l'oggetto. L'idea è che puoi chiamare Dispose sull'oggetto senza dover tornare alla raccolta per trovarlo, e farlo automaticamente causa la rimozione dalla raccolta del contenitore. L'evento viene utilizzato internamente dal framework (è persino contrassegnato come interno per non essere utilizzato all'esterno) e il gestore lo rimuove dalla raccolta. – ctacke
Ho aggiornato la domanda per aggiungere la gestione degli eventi per maggiore chiarezza. – ctacke