2009-09-18 11 views
19

Sto cercando di scrivere su un'API e ho bisogno di chiamare un eventhandler quando ottengo i dati da una tabella. Qualcosa di simile a questo:Passare un valore di ritorno attraverso un EventHandler

public override bool Run(Company.API api) 
    { 
     SomeInfo _someInfo = new SomeInfo(); 

     if (_someInfo.Results == 1) 
      return true; 
     else 
      return false; 

     using (MyTable table = new MyTable(api)) 
     { 
      table.WhenData += new EventHandler<DataEventArgs<Record>>(table_WhenData); 
      table.WhenDead += new EventHandler<EventArgs>(table_WhenDead); 
      table.Start(); 
     } 

    public void table_WhenData(object sender, DataEventArgs<Record> e) 
    { 
     return true; 
    } 

Il problema che Im che ha è che io non so come passare un valore di ritorno indietro dal table_WhenData al metodo Run.

Ive ha provato in molti modi (come provare a passare _someInfo al metodo) ma non riesco a ottenere la sintassi corretta.

Qualsiasi suggerimento è molto apprezzato.

+0

il gestore di eventi deve essere chiamato da qualche parte. questo non è mostrato nel tuo codice? Questo è l'unico posto in cui puoi controllare il ritorno dal gestore. – simon

+0

Grazie a tutti.Poiché si tratta di un'API, gran parte del codice non ha accesso o non posso cambiare. Volevo solo verificarlo prima di inviarlo agli sviluppatori. Grazie. –

+2

Più uno sul nome utente –

risposta

38

Lo schema comune qui non è quello di restituire alcun dato dal gestore eventi, ma di aggiungere proprietà all'oggetto argomento evento in modo che l'utente dell'evento possa impostare le proprietà a cui il chiamante può accedere. Questo è molto comune nel codice di gestione dell'interfaccia utente; vedi il concetto di evento Annulla ovunque.

Quanto segue è uno pseudo codice e non è pronto per la compilazione. Il suo intento è mostrare lo schema.

public MyEventArgs : EventArgs 
{ 
    public bool Cancel{get;set;} 
} 

public bool fireEvent() 
{ 
    MyEventArgs e=new MyEventArgs(); 

    //Don't forget a null check, assume this is an event 
    FireEventHandler(this,e); 

    return e.Cancel; 
} 

public HandleFireEvent(object sender, MyEventArgs e) 
{ 
e.Cancel=true; 
} 

Modifica

Mi piace come Jon Skeet formulata questo: rendere il mutuable EventArgs. Cioè, il consumatore dell'evento può modificare lo stato dell'oggetto EventArgs consentendo al raiser dell'evento di accedere a tali dati.

+1

Nel caso in cui vi siano più gestori di eventi (alcuni lo impostano su true e altri impostano il valore di questo oggetto su false, per l'esempio di codice indicato sopra), come determina il codice di sottoscrizione dell'evento? è come l'ultimo abbonato che set vince – bashahul

+1

Buona domanda probabilmente vorresti usare una struttura dati diversa in questo caso, a seconda delle regole di business che hai – JoshBerke

15

L'unico modo per farlo è rendere modificabile uno degli argomenti (preferibilmente gli "arg" piuttosto che il mittente). Se non è già mutabile, hai fondamentalmente dei problemi: non c'è modo di estrarre l'informazione.

(Va bene, c'è un modo - è possibile mantenere l'argomento evento stesso immutabile, ma fare un membro di essa un metodo che finisce per chiamare un delegato registrato dal codice di verifica l'anomalia, in primo luogo, ma questo è orribile.. ..)

+2

La mia testa fa male a cercare di capire l'unico modo per rendere mutevole l'EventArgs! – JoshBerke

+0

E riguardo l'uso di una chiusura come descritto nella mia risposta? –

+0

Igor: Funzionerebbe, ma di solito il bit di codice che richiede il risultato non è il bit di codice che sottoscrive l'evento. –

1

una soluzione semplice è quella di utilizzare una chiusura:

public override bool Run() { 
    SomeInfo someInfo = ... 
    table.WhenData += (obj, args) => { 
     someInfo.Return = something 
    }; 
} 
+0

la preoccupazione che potrei avere con questa soluzione, sono i problemi di concorrenza. Un thread che chiama l'evento, un altro che legge la variabile someInfo prima che la scrittura sia completata. Avrebbe bisogno di una protezione multi-thread di qualche tipo. – simon

17

so che questo è un vecchio post, ma solo nel caso in cui qualcuno viene attraverso di esso, è certamente possibile farlo. Si dichiara il proprio delegato che restituisce un valore, quindi basare l'evento su questo nuovo delegato. Ecco un esempio:

In caso dichiarante/editore:

// the delegate 
public delegate string ReturnStringEventHandler(object sender, EventArgs args); 
// the event 
public event ReturnStringEventHandler StringReturnEvent; 
// raise the event 
protected void OnStringReturnEvent(EventArgs e) 
    { 
     if (StringReturnEvent != null) // make sure at least one subscriber 
       // note the event is returning a string 
       string myString = StringReturnEvent(this, e); 
    } 

In sottoscrittore dell'evento:

// Subscribe to event, probably in class constructor/initializer method 
StringReturnEvent += HandleStringReturnEvent; 

// Handle event, return data 
private string HandleStringReturnEvent(object sender, EventArgs e) 
{ 
    return "a string to return"; 
} 

.NET fornisce un esempio di questo nel caso AssemblyResolve, che utilizza il ResolveEventHandler delegato per restituire i dati, in questo caso un riferimento all'assembly desiderato. MSDN Article on AssemblyResolve event

Personalmente ho usato sia l'evento AssemblyResolve e la tecnica delegato personalizzato per restituire i dati da un evento, ed entrambi lavorano come previsto in Visual Studio 2010.

+2

Se si utilizza l'approccio delegato personalizzato, cosa succede se si hanno più gestori dell'evento che restituiscono valori diversi? Quale valore di ritorno viene ricevuto dal raiser dell'evento? – Shavais

+0

Hai accennato a un netto richiamo a questo approccio. L'ultimo gestore di eventi da registrare con l'evento è quello il cui valore sarà restituito. http://msdn.microsoft.com/en-us/library/aa691375%28VS.71%29.aspx Nell'evento "AssemblyResolve" che ho menzionato, questo è OK, dal momento che è destinato solo a essere utilizzato uno alla volta, ma hai ragione - in generale, questa sarebbe una scelta di design scadente se sono richiesti più valori di ritorno. – AFischbein

+0

Brillante. Grazie ! – BillW

Problemi correlati