2010-05-12 3 views
10

In una forma, confrontareQual è la differenza tra Invocare e BeginInvocare un MessageBox?

BeginInvoke (new Action (() => { 
    MessageBox.Show()); 
})); 

con

Invoke (new Action (() => { 
    MessageBox.Show()); 
})); 

Qual è la differenza, e quando devo usare uno sopra l'altro? Com'è influenzato il comportamento dal message pump del MessageBox?

Ho eseguito alcuni test e ho riscontrato che i metodi entrambi bloccano l'interfaccia utente.

L'unica differenza è che Invoke viene effettivamente chiamato istantaneamente mentre BeginInvoke richiede un tempo (molto breve) finché il codice non viene eseguito. Questo è normale.

+0

A tutti i rispondenti: Scusa, al momento non ci sono voti, andare a votare domani :) – mafu

risposta

15

invocherà il delegato in modo asincrono, restituendo immediatamente dopo aver accodato il delegato per l'esecuzione indipendentemente dal thread corrente.

Invoke invocherà il delegato in modo sincrono, bloccando il thread chiamante fino al completamento del delegato.

Per vedere la differenza, provare il seguente codice:

BeginInvoke(new Action(()=>Console.WriteLine("BeginInvoke"))); 
Console.WriteLine("AfterBeginInvokeCalled"); 

Invoke(new Action(()=>Console.WriteLine("Invoke"))); 
Console.WriteLine("AfterInvokeCalled"); 

Si dovrebbe vedere un output simile al seguente, in cui il testo "BeginInvoke" è in ritardo a causa della sua esecuzione asincrona:

AfterBeginInvokeCalled
Invoke
AfterInvokeCalled
BeginInvoke

Riguardo al comportamento che si osserva, in quanto è solo l'atto di chiamare il delegato che è sincrono o asincrono; il contenuto del metodo potrebbe causare l'interruzione del thread chiamante o l'interruzione dell'interfaccia utente. Nel caso in cui venga visualizzata una finestra di messaggio, indipendentemente dal fatto che il delegato ritardi o meno usando BeginInvoke o meno, una volta chiamato il delegato, l'interfaccia utente verrà bloccata fino alla sua chiusura.

3

BeginInvoke è asincrono ... ciò significa che il thread chiamante non attenderà il ritorno del metodo chiamato.

Quindi ok, la finestra di dialogo blocca sempre la GUI. Ma la differenza tra invocare invoke e invoke dovrebbe essere ora chiara:

Invoke attende che il metodo chiamato restituisca BeginInvoke no.

+0

Non sono d'accordo. Vedi domanda modificata. --- Modifica: Ah, sì, ma i MessageBox non sono sempre modali? – mafu

+0

@mafutcrt: Penso che tu abbia confuso due cose. MessageBox continuerà a bloccare l'interfaccia utente, ma l'atto effettivo di chiamare il metodo lambda è asincrono quando viene chiamato tramite BeginInvoke. Solo perché quella chiamata è asincrona non significa che il risultato della chiamata sarà. –

+0

@Jeff: Sì, è vero. Suggerisco a @ Simon di includere questa spiegazione nella sua risposta per renderlo più chiaro. – mafu

1

Per un MessageBox.Show, la domanda è per lo più irrilevante.

La differenza solo è che con il BeginInvoke, il chiamando filo sé non bloccare, in modo che possa continuare a fare le cose (pulizia, ulteriori elaborazioni, ecc).

Il thread dell'interfaccia utente ovviamente si bloccherà, perché è presente una finestra modale che attende l'input dell'utente per chiuderla.

14

Simon in realtà non si sbaglia.

BeginInvoke è come inviare un messaggio al thread dell'interfaccia utente e dire "Fai questo appena ne hai la possibilità".

Invoke è come dire "Fai questo al momento. Ti aspetto."

Precisazione: solo perché si dire thread UI, "Fate questo in questo momento," questo non significa che tu sei Dio del thread dell'interfaccia utente e può costringerlo a mollare tutto che sta facendo. Fondamentalmente, le parole chiave nella dichiarazione di cui sopra sono "Aspetterò".

Il fatto è che, nel codice di esempio, il messaggio che si sta inviando al thread dell'interfaccia utente è: chiamare MessageBox.Show. Indovina un po? Ciò bloccherà il thread dell'interfaccia utente in entrambi i casi.

Se si vuole notare il comportamento asincrono di BeginInvoke, chiamare da un thread separato, mettere un punto di interruzione dopo la BeginInvoke chiamata nel codice, e notare che il punto di interruzione viene colpito anche mentre si visualizza la finestra di messaggio (e la L'interfaccia utente è bloccata). Se si chiama Invoke, il codice non continuerà finché l'utente non chiude la finestra di messaggio.

+1

Questa è la spiegazione che stavo cercando :) – mafu

+1

Buona spiegazione. Volevo solo sottolineare che sia BeginInvoke che Invoke entrambi dicono "Fai questo appena ne hai la possibilità.", Ma Invoke aggiunge anche "E aspetterò fino al termine". Invoke non è in grado di affrettare le cose, come hai suggerito ("Fai questo adesso"). –

+0

@ Allon: Sì, immagino che sia un po 'soggettivo come interpreti quelle parole. Il fatto è che in * real * life, tu * non * puoi ** fare ** qualcuno fare qualcosa ** in questo momento ** - ma puoi * dirlo * a farlo "adesso" e stare lì con le braccia incrociate, toccando il piede fino a quando non l'hanno effettivamente fatto. Per me, questo è l'intento di "Invoke" - hai ragione che non è come se tu potessi costringerlo ad abortire qualunque codice sia attualmente in esecuzione; ma stai effettivamente * dicendo *, almeno, "Fai questo adesso." –

2

Mentre la maggior parte delle risposte sono tecnicamente corrette, non fanno la domanda ovvia.

Perché si desidera racchiudere le chiamate MessageBox() in Invoke/BeginOnvoke in primo luogo?

Non c'è alcun vantaggio nell'utilizzo di BeginInvoke o Invoke in questa situazione, come ha spiegato Jeff.

Sembra che tu stia confondendo tra l'utilizzo di Invoke/BeginInvoke su un modulo/controllo di Windows in una situazione a più thread e l'utilizzo di Invoke/BeginInvoke su un'istanza delegata (ad esempio il modello di programmazione Asynchornous).

Questo è facile da fare poiché i nomi sono ovviamente identici, tuttavia gli scenari che useresti e il loro comportamento è diverso.

Il libro CLR Via C# fornisce una buona spiegazione di entrambi i tipi di Invoke/BeginInvoke.