2009-02-10 14 views

risposta

53

Delegate.EndInvoke è documentato come avrai chiamano questo (cioè necessario - perdite altro accada) - da msdn:

Nota importante

Indipendentemente dalla tecnica utilizzata, chiama sempre EndInvoke per completare il c asincrono c tutti.

Control.EndInvoke è OK per ignorare per il fuoco-e-dimentica metodi - da msdn:

È possibile chiamare EndInvoke per recuperare il valore di ritorno dal delegato, se neccesary, ma questo non è richiesto.

Tuttavia - se si utilizza Delegate.BeginInvoke e non si desidera che il risultato, è consigliabile utilizzare ThreadPool.QueueUserWorkItem invece - vi rendono la vita molto più facile, e di evitare il dolore di IAsyncResult ecc

+0

Grazie a Marc, questo è ciò che ha motivato la domanda: stavo guardando attraverso Richter e ho notato QueueUserWorkItem, e ho pensato "aspetta, perché sto usando BeginInvoke/EndInvoke altrove". – endian

+0

@endian - infatti: la maggior parte dell'utilizzo di BeginInvoke può essere fatto più semplicemente con ThreadPool; il BeginInvoke è forse utile per fare alcune cose e riunirle di nuovo in seguito ... –

+0

Illuminato. Grazie! – rpattabi

18

EndInvoke non è facoltativo.

Maggiori informazioni here

+0

Grazie Luca - risposta accettata. – endian

+1

... per i delegati, almeno ;-p –

+6

dal tuo collegamento: "L'unica eccezione documentata alla regola di cui sono a conoscenza è in Windows Form, in cui ti è ufficialmente permesso di chiamare Control.BeginInvoke senza preoccuparti di chiama Control.EndInvoke. " – Avram

9

e call EndInvoke non è una chiamata opzionale, è una parte del contratto. Se chiami BeginInvoke, devi chiamare EndInvoke.

Classico esempio del motivo per cui è necessario. È molto probabile che IAsyncResult restituito da BeginInvoke abbia assegnato risorse ad esso associate. Più comunemente un WaitHandle di sorta. Poiché IAsyncResult non implementa IDisposable, è necessario scegliere un altro posto per liberare le risorse. L'unico posto per farlo è EndInvoke.

Discuto brevemente di questo problema nel seguente post del blog.

http://blogs.msdn.com/jaredpar/archive/2008/01/07/isynchronizeinvoke-now.aspx

+0

Grazie Jared, molto apprezzato. – endian

4

EndInvoke non è un optional, perché è il luogo in cui vengono generate eccezioni se qualcosa è andato storto nella lavorazione asincrono.

In ogni caso non ci dovrebbero essere perdite perché se IAsyncResult è in possesso di qualche risorsa nativa dovrebbe implementare correttamente IDisposable e disporre tali risorse quando il GC chiama il suo finalizzatore.

2

È l'unico optional se non ti dispiace che la memoria del tuo programma cresca molto. Il problema è che il GC trattiene tutti i riferimenti nel tuo thread, perché potresti voler chiamare EndInvoke ad un certo punto. Vorrei andare con la risposta di Marc, il threadpool renderà la vita più facile. Tuttavia, è necessario prestare attenzione se si generano i thread dai thread, in quanto è limitato dal numero di thread che può far ruotare.

3

Non è opzionale perché chiamare BeginInvoke fa uso di WaitHandle che a sua volta utilizza un oggetto kernel che mantiene un conteggio per il numero di riferimenti necessari.La chiamata EndInvoke elimina con garbo l'handle che decrementa quel contatore sull'oggetto kernel e quando tale conteggio raggiunge lo zero, il gestore oggetti del kernel lo distruggerà.

2

Ogni risposta in questo post indica che EndInvoke() non è facoltativo. Tuttavia, ho trovato il seguente commento altamente classificato che è la risposta accettata su questo thread SO:

"Si noti che il team di Windows Form ha garantito che è possibile utilizzare Control.BeginInvoke in modo 'fire and forget' - cioè senza mai chiamare EndInvoke. Questo non è vero per le chiamate asincrone in generale: normalmente ogni BeginXXX dovrebbe avere una chiamata EndXXX corrispondente, solitamente nel callback. "

What's the difference between Invoke() and BeginInvoke()

+0

IMHO, è un peccato che 'Control.BeginInvoke' e' Delegate.BeginInvoke' condividano lo stesso nome, dato che hanno semantica totalmente diversa; a dire il vero, sono curioso di sapere perché i tipi delegati definiscono 'BeginInvoke' è un metodo di istanza, piuttosto che avere' Delegate.Bind (params) 'restituisce un' MethodInvoker' [delegato a zero argomenti] che invocherebbe il delegato con i parametri specificati e che potrebbero essere passati ad es un metodo 'ThreadPool.BeginInvoke'. – supercat

+0

+1 per questa importante distinzione. L'onnisciente commento di Skeet (citato sopra) è molto rilevante per chi considera le situazioni Control.InvokeRequired. –

Problemi correlati