2012-02-16 6 views
22

È disapprovato modificare EventArgs nei gestori di eventi allo scopo di passare di nuovo le informazioni alla classe che richiama l'evento?Utilizzo di EventArgs per passare le informazioni alla classe di richiamo

Per esempio se ho una classe di comunicazione di basso livello che ha bisogno di convalidare un certificato per SSL ma non ha modo di sapere che aspetto ha un certificato valido poiché questa è la conoscenza dei diversi utenti della classe.

class ValidationEventArgs : System.EventArgs 
{ 
    public X509Certificate Certificate { get; set; } 
    public bool Valid { get; set; } 
} 

Poi negli oggetti che utilizzano gancio fino alla manifestazione, e controllare in qualche modo cambiare la bandiera Valid per indicare se il certificato è accettabile o meno.

comms.ValidationEvent += CertValidationHandler; 

void CertValidationHandler(ValidationEventArgs args) 
{ 
    if (args.Certificate.Issuer.Contains(COMPANY_NAME) 
     args.Valid = true; 
} 

ho trovato references di EventArgs in uso come questo, ma ho anche visto gente dicendo che non è raccomandato.

Modifica: Forse dovrei chiarire che non si tratta di ereditare EventArgs, ma di utilizzarli come canale di comunicazione bidirezionale. Come altri hanno commentato, questo è accettabile e qualsiasi rumore di Google assuma l'opposto è probabilmente solo la gente che ha frainteso/usato impropriamente il concetto e ora ha la stessa crociata personale contro come goto.

+6

Chi dice che non è raccomandato? Questo succede tutto il tempo nel quadro. Guarda ['CancelEventArgs'] (http://msdn.microsoft.com/en-us/library/system.componentmodel.canceleventargs.aspx); non ha molto più di base. –

+0

Googling around Ho la sensazione che avere EventArgs mutabile non sia qualcosa che si dovrebbe fare, probabilmente perché qualcuno lo ha abusato a un certo punto. Grazie –

+0

Come per le cose, ha il tempo e il luogo per usarlo, usarlo nel modo sbagliato e il posto è cattivo, ma questo non lo rende negativo. – MikeT

risposta

41

Ponendosi la seguente domanda, "quando pubblico un evento, voglio che ogni sottoscrittore modifichi uno dei valori di EventArgs"? Se la risposta è no, ad es. state trasmettendo informazioni di sola lettura e rendete la classe immutabile, tuttavia se avete bisogno di feedback da parte di un sottoscrittore, rendete mutevoli le proprietà che devono essere modificate.

Per chiarire, in un esempio di trasmissione, vogliamo dire qualcosa a qualsiasi sottoscrittore ma non lasciare che alterino il valore.

public class ProgressEventArgs : EventArgs 
{ 
    public ProgressEventArgs(int current) 
    { 
     this.Current = current; 
    } 

    public int Current { get; private set; } 
} 

Allo stesso modo, potremmo anche sollevare un evento per chiedere informazioni che la classe stessa non conosce.

public class FeedbackEventArgs : EventArgs 
{ 
    public bool ShouldContinue { get; set; } 
    public string Reason { get; set; } 
} 
+0

Mi è piaciuto, mostra le domande giuste da porsi. –

+2

So che questo è vecchio, ma vorrei sottolineare che si dovrebbe fare attenzione quando si utilizza questo approccio in quanto potrebbero esserci più di un sottoscrittore per evento, ma sarebbe lo stesso oggetto evento che viene passato in giro in modo da poter utilizzare semplici setter causare la sovrascrittura dei dati. – Pharap

+0

@Pharap buon punto! Nell'esempio mutevole, sarebbe il caso di "ultime vittorie di scrittura" –

2

Non sono a conoscenza di alcuna raccomandazione contro l'ereditarietà da EventArgs; per quanto ne so, ereditarlo è una buona pratica.

Come principio generale, suggerisco di rendere immutabili le classi derivate. Ciò renderà molto più sicuro passare tra i thread nel caso fosse necessario. Il modo più semplice per farlo è dichiarare le proprietà come { get; private set; } e impostarle solo nel costruttore. Ovviamente non puoi farlo con il caso d'uso specifico che hai nella domanda, ma dovresti farlo dove possibile.

+0

+1 - d'accordo. Usato questo metodo un sacco di volte. – ChrisBD

+0

sì, ho semplificato eccessivamente l'esempio, l'unico parametro mutabile sarebbe il booleano. La domanda consisteva nell'usare eventi per trasmettere i dati all'invoker, fondamentalmente come un canale bidirezionale, non ereditando EventArgs. L'unico problema che riesco a vedere potrebbe riguardare più listener/thread, ma le specifiche in cui verrà utilizzato non lo consentono. –

7

È possibile utilizzare la classe EventArgs tramite l'approccio Tipi generici. In questo esempio, userò la classe Rect con come tipo di ritorno:

public EventHandler<Rect> SizeRectChanged; 

Alzare l'evento:

if(SizeRectChanged != null){ 
    Rect r = new Rect(0,0,0,0); 
    SizeRectChanged(this,r); 
} 

ascolto dell'evento:

anyElement.SizeRectChanged += OnSizeRectChanged; 

public void OnSizeRectChanged(object sender, Rect e){ 
    //TODO abything using the Rect class 
    e.Left = e.Top = e.Width = e.Height = 50; 
} 
+1

Questo non funzionerà perché EventHandler ha il vincolo di 'where TEventArgs: EventArgs'. Ciò significa che il tipo generico deve essere derivato da EventArgs. Cercando di utilizzare un Rect comporterà un errore del compilatore. – BrandonLWhite

+4

Il vincolo per l'ereditazione di EventArgs è stato eliminato in .net 4.5. – Dashu

Problemi correlati