2015-05-27 26 views
7

Ho il seguente codice nella mia classeÈ possibile utilizzare l'assegnazione di uguali quando si rimuovono membri delegati in un metodo di smaltimento?

public class Receiver : IReceiver 
{ 

    public event EventHandler Received; 

    public void Dispose() 
    { 
     Dispose(true); 
     GC.SuppressFinalize(this); 
    } 

    protected virtual void Dispose(bool disposing) 
    { 
     if (disposing) 
     { 
      if (Received != null) 
      { 
       foreach (EventHandler delegateMember in Received.GetInvocationList()) 
       { 
        Received -= delegateMember; 
       } 
      } 
     } 
    } 
} 

Questo codice funziona in che quando mi dispongo la mia classe tutti gli eventi che sono collegati alla manifestazione Ricevuto, saranno rimossi singolarmente.

mi sono chiesto se, piuttosto che essere così verbose a questo proposito, se la seguente versione concisa avrà lo stesso effetto

protected virtual void Dispose(bool disposing) 
    { 
     if (disposing) 
     { 
      Received = null; 
     } 
    } 

Fondamentalmente questo si riduce a come i sovraccarichi operatore sono stati creati da Microsoft quando implementare i sovraccarichi dei delegati. So che tutta la documentazione dice di usare + = per iscriversi e - = per annullare l'iscrizione a un evento. Ho anche visto il documento dire che l'evento verrà assegnato a null quando l'ultimo utente viene rimosso. Ciò che la documentazione non dice è se l'assegnazione dell'evento a null, avrà l'effetto di annullare la sottoscrizione di tutti gli eventi?

Mi piacerebbe sapere se questo è possibile, e se c'è qualche documentazione che dice che l'eventuale codice terse è un comportamento corretto.

Aggiornamento:

Ho fatto un po 'scavare con il compilatore C# e hanno trovato che l'assegnazione su null funziona solo all'interno della classe in cui è definito l'evento. + = E - = è sempre disponibile sia all'interno che all'esterno della classe. Questo mi porta a pensare che usare la versione = null sia accettabile. Tuttavia, questa è una speculazione, non ho ancora visto alcuna documentazione che dichiari esplicitamente che questa è una funzionalità supportata.

+3

@DStanley I delegati farebbero ancora riferimento a tali oggetti, sì, ma il delegato stesso non verrebbe più rootato o accessibile da una radice, quindi non manterrebbe vivi quegli oggetti di riferimento. – Servy

+0

Ho controllato per un po 'di tempo prima di pubblicare la domanda. Bascialmente la domanda sta usando = versi usando - =. Nel MSDN il più vicino che riesco a trovare è in fondo a questa pagina https://msdn.microsoft.com/en-us/library/ms366768(v=vs.90).aspx dice che il null verrà assegnato quando l'ultima istanza del gestore eventi è stata annullata. –

risposta

4

Non c'è motivo per non assegnare semplicemente il numero null al delegato.

Non saresti in grado di assegnare solo null se eri al di fuori della classe che ha definito l'evento. Per chiunque utilizzi la classe dovrebbero preoccuparsi solo dei propri gestori, che possono aggiungere o rimuovere. Non sono in grado di accedere ai gestori degli altri.

È necessario ricordare che i delegati sono immutabili. L'utilizzo di += in un evento non muta il delegato per aggiungere un nuovo metodo a tale delegato, crea un nuovo delegato che, una volta chiamato, chiama entrambi i delegati che sono stati aggiunti insieme. L'utilizzo di -= crea un delegato che richiama tutte le chiamate del primo operando ad eccezione del secondo operando. Quindi chiamare più volte -= crea sempre più delegati che invocano sempre meno roba, finché alla fine si arriva al punto che il delegato non sta invocando più nulla. Assegnare semplicemente null equivale a creare un delegato che non fa nulla e assegnarlo direttamente.

Quindi quando si chiama -= più e più volte il delegato originale che è stato assegnato all'evento prima dell'inizio esiste ancora, così come N delegati intermedi. Detto questo, a nessuno dei delegati è probabile che venga fatto riferimento da alcun elemento rooted, quindi saranno tutti idonei per la raccolta. Se assegni solo a null hai ancora lo stesso delegato orfano che era originariamente lì, non hai più nessuno dei delegati intermedi.

+0

Capisco tutto ciò che hai postato qui, e so che il codice verrà compilato in entrambi i modi. Suppongo che la parte fondamentale della domanda sia ... è che - = fare anche qualcos'altro, ma l'assegnazione = non sta facendo? E se è così puoi essere sicuro? L'unico riferimento che si avvicina a questo che ho trovato finora è in fondo a questa pagina https://msdn.microsoft.com/en-us/library/ms366768(v=vs.90).aspx che esplicitamente dice di usare l'operatore - =. Si dice che puoi verificare null per vedere se ci sono abbonati. Non dice che puoi usare l'operatore =. –

+0

@ColinDawson L'operatore '- =' non sta facendo nulla oltre alla creazione di un nuovo delegato che esclude il secondo operando dall'elenco di richiami e quindi assegna quel nuovo delegato al primo operando. Creare un nuovo delegato che non fa nulla (a.k.a. 'null') e assegnarlo direttamente è quindi equivalente. Naturalmente, a meno che nessuno dei gestori di eventi faccia riferimento all'oggetto che definisce l'evento (e sopravviva a questo ricevitore), non c'è motivo di fare * * *, poiché l'intero ricevitore dovrebbe presto cessare di essere radicato in primo luogo. nessun motivo per annullarlo. – Servy

+0

Capisco che, la domanda è no, puoi scriverlo in codice, ma c'è qualche documentazione che supporti using = null? Mi piacerebbe essere in grado di usare semplicemente il codice tergente perché sembra estremamente chiaro, ma voglio essere sicuro che sotto il cofano tutto funzioni come previsto - allo stesso modo del codice dettagliato dell'esempio. Quello che sto cercando è la citazione che dice che è un costrutto ammissibile. Non voglio presumere che funzioni. Quello che dici ha senso, capirò come sei arrivato a quella comprensione. –