2010-03-28 11 views
12

C'è un modo semplice per iterare su tutti gli handler abbonati a un determinato evento? Il mio problema è che i clienti si iscrivono ma si dimenticano di annullare l'iscrizione in modo che si verifichi una perdita di memoria. Ho bisogno di un modo per un oggetto per disconnettere tutti i gestori dei suoi eventi nel metodo Dispose in modo che non si verifichi una perdita, almeno non a causa di eventi.C# Come annullare l'iscrizione a tutti i gestori di eventi da un determinato evento?

risposta

11

Set nulla al vostro evento: MyEvent = null;

Ma è davvero meglio per rendere i clienti cancellarsi dal vostro evento.

+1

Non è possibile impostare un evento a null, in C#. –

+8

In realtà è possibile, se ci si trova all'interno della classe in cui è stato dichiarato l'evento. –

+1

Sei corretto. –

9

Un approccio alternativo consiste nell'utilizzare il cosiddetto modello "delegato debole". Quando si utilizza questa tecnica, l'evento fa riferimento ai client solo utilizzando WeakReference che non li tiene in memoria. I client verranno raccolti automaticamente quando non vengono più referenziati da altre parti dell'applicazione (e il gestore può anche essere annullato automaticamente quando viene raccolto il client).

Questo è in genere utilizzato per risolvere il problema con i client "dimenticandosi" di annullare l'iscrizione a un evento .NET, quindi sembra che questo potrebbe essere adatto per il tuo problema.

7

La perdita di memoria si verifica solo se un altro oggetto (listener) muore prima dell'oggetto (origine evento). In questo caso, l'origine evento conserva ancora il riferimento al listener, che impedisce la raccolta del listener. Quando l'origine dell'evento muore, può essere raccolto anche l'ascoltatore non iscritto.

Se l'origine dell'evento muore prima dell'ascoltatore, ciò non impedisce che il listener venga raccolto in seguito, quando tutti gli altri riferimenti ad esso sono impostati su null.

Questo significa che il metodo di eliminazione della fonte di eventi non è corretto per risolvere questo problema. Può essere risolto solo in un codice listener. Semplicemente parlando, non puoi fare nulla, tranne chiedere ai tuoi clienti di scrivere codice pulito.

1

Al momento della scrittura, la risposta più accurata è la meno popolare.

È possibile annullare l'event handler, ma questo sarebbe comunque rimosso dopo che il suo proprietario è stato rimosso (non è sbagliato essere in ordine, ma come dice Alex, non è dove si trova il problema.

La classe di origine di Adi consentirà di raccogliere gli oggetti in ascolto quando vengono raccolti, non c'è dubbio. Quindi il problema è che l'oggetto sorgente di Adi viene tenuto aperto, probabilmente da una lunga catena di riferimenti nel codice del suo cliente.

Il seguente post sul blog analizza anche una soluzione che Adi sta decifrando e spiega perché non è necessaria.

http://weblogs.sqlteam.com/mladenp/archive/2007/10/24/C-Care-about-Event-Memory-Leaks-with-Delegate.GetInvocationList.aspx

Problemi correlati