2012-06-24 4 views
92

Quando si utilizza myDelegate -= eventHandler ReSharper (versione 6) problemi:"La sottrazione del delegato ha un risultato imprevedibile" in ReSharper/C#?

Delegato sottrazione ha risultato imprevedibile

Il razionale dietro questo è explained by JetBrains here. La spiegazione ha senso e, dopo averlo letto, dubito di tutti i miei usi di - sui delegati.

Come dunque,

  • posso scrivere un evento non-auto senza fare ReSharper scontroso?
  • o, c'è un modo migliore e/o "corretto" per implementare questo?
  • oppure, posso semplicemente ignorare ReSharper? Codice

Qui è semplificato:

public delegate void MyHandler (object sender); 

MyHandler _myEvent; 

public event MyHandler MyEvent 
{ 
    add 
    { 
     _myEvent += value; 
     DoSomethingElse(); 
    } 
    remove 
    { 
     _myEvent -= value; // <-- ReSharper warning here 
    } 
} 
+0

Mono dà lo stesso avviso. Ecco la descrizione di R # del problema https://confluence.jetbrains.com/display/ReSharper/Delegate+subtraction+has+unpredictable+semantics (che si applica solo agli elenchi di delegati) – thoredge

risposta

107

Non abbiate paura! La prima parte dell'ammonizione di ReSharper si applica solo alla rimozione di elenchi di delegati. Nel tuo codice, rimuovi sempre un singolo delegato. La seconda parte parla dell'ordine di delegati dopo la rimozione di un delegato duplicato. Un evento non garantisce un ordine di esecuzione per i suoi abbonati, quindi non ha alcun effetto su di te.

Poiché la meccanica di cui sopra può portare a risultati imprevedibili, ReSharper emette un avviso ogni volta che incontra un operatore di sottrazione delegato.

ReSharper sta emettendo questo avviso perché la sottrazione di delegati multicast può avere dei trucchi, non sta condannando completamente quella caratteristica del linguaggio. Fortunatamente quei trucchi sono nei casi marginali ed è improbabile che li incontriate se state semplicemente strumentando eventi semplici. Non esiste un modo migliore per implementare i tuoi gestori add/remove, devi solo notarlo.

Suggerire di eseguire il downgrade del livello di avviso di ReSharper per quel messaggio a "Suggerimento" in modo da non essere desensibilizzati ai propri avvisi, che di solito sono utili.

+0

Mi sento un po 'meno schizzinoso già :) –

+51

Penso che sia male di R # per chiamare i risultati "imprevedibili". Sono specificati molto chiaramente. "Non quello che l'utente potrebbe prevedere" non è in alcun modo la stessa cosa di "imprevedibile". (È anche impreciso dire che il framework .NET definisce gli overload - è inserito nel compilatore C#. "Delegate' fa * not * overload' +' e '-'.) –

+6

@Jon: Sono d'accordo. Immagino che tutti si siano abituati alla barra alta che Microsoft si è imposta da sola. Il livello di levigatezza è alto così com'è, con così tante cose nel mondo .NET che ti fanno "cadere nella fossa del successo", incontrando una caratteristica linguistica che è una semplice camminata a passo ravvicinato al pozzo dove c'è un possibilità che tu possa mancare è considerato da alcuni di essere stridente e garantisce un cartello che dice "PIT DI SUCCESSO È CHE MODO --->". –

-13

set a = null invece di utilizzare - =

+3

il metodo 'remove' di un evento non dovrebbe rimuovere tutti i gestori, ma piuttosto il gestore che è stato richiesto di essere rimosso. – Servy

+0

se ne ha aggiunto uno solo, se rimuove solo uno in effetti li ha rimossi tutti. Non sto dicendo di usarlo in tutti i casi solo per questo specifico messaggio di resharper. –

+3

Tuttavia * non * sa che il delegato rimuove sempre l'unico elemento nell'elenco di chiamate. Questo fa svanire il messaggio di resharper trasformando il codice corretto in codice errato che, in certe circostanze, funzionerà casualmente, ma in molti casi si interromperà in modi insoliti e difficili da diagnosticare. – Servy

9

Non dovrebbe usare direttamente i delegati per sommare o sottrarre. Invece il tuo campo

MyHandler _myEvent; 

Dovrebbe essere dichiarato come evento. Ciò risolverà il problema senza rischiare la soluzione e continuerà a beneficiare dell'utilizzo degli eventi.

event MyHandler _myEvent; 

L'utilizzo di somma delegato o sottrarre è pericoloso perché si può perdere gli eventi quando semplicemente assegnando il delegato (come da dichiarazione, lo sviluppatore non inferire direttamente questo è un delegato multicast come quando si è dichiarato come un evento) . Giusto per esemplificare, se la proprietà menzionata in questa domanda non è stata contrassegnata come un evento, il codice seguente farà sì che i primi due incarichi siano LOST, perché qualcuno semplicemente ha assegnato al delegato (che è anche valido!).

myObject.MyEvent += Method1; 
myObject.MyEvent += Method2; 
myObject.MyEvent = Method3; 

Quando si assegnano method3, ho completamente perso le due sottoscrizioni iniziali. L'utilizzo degli eventi eviterà questo problema e allo stesso tempo rimuoverà l'avviso di ReSharper.

+0

Non ho mai pensato di farlo in questo modo, ma ha senso proteggere l'utilizzo dei delegati dell'evento finché si mantiene privato l'evento sottostante. Questo tuttavia non funziona bene quando ci sono più specifiche sincronizzazione dei thread che devono verificarsi nei gestori di aggiunta/rimozione come più sottoscrizioni di eventi o sotto-abbonamenti che devono essere monitorati. Tuttavia, in ogni caso rimuove gli avvertimenti. – Jeremy