Perché il metodo di delega asincrono richiede la chiamata a EndInvoke?

Perché il delegato deve chiamare EndInvoke prima che il metodo venga triggersto? Se ho bisogno di chiamare EndInvoke (che blocca il thread), allora non è una chiamata asincrona?

Ecco il codice che sto cercando di eseguire.

class Program { private delegate void GenerateXmlDelegate(); static void Main(string[] args) { GenerateXmlDelegate worker = new GenerateXmlDelegate(GenerateMainXml); IAsyncResult result = worker.BeginInvoke(null, null); } private static void GenerateMainXml() { Thread.Sleep(10000); Console.WriteLine("GenerateMainXml Called by delegate"); } } 

Il motivo per cui è necessario chiamare EndInvoke è evitare perdite di memoria; .Net memorizzerà le informazioni sul risultato (o sull’eccezione) della funzione finché non si chiama EndInvoke .

Puoi chiamare EndInvoke nel gestore di completamento che dai a BeginInvoke e mantenere la natura asincrona.

MODIFICA :

Per esempio:

 class Program { private delegate void GenerateXmlDelegate(); static void Main(string[] args) { GenerateXmlDelegate worker = new GenerateXmlDelegate(GenerateMainXml); IAsyncResult result = worker.BeginInvoke(delegate { try { worker.EndInvoke(); } catch(...) { ... } }, null); } private static void GenerateMainXml() { Thread.Sleep(10000); Console.WriteLine("GenerateMainXml Called by delegate"); } } 

Se vuoi triggersre una chiamata asincrona e dimenticarla, puoi utilizzare il ThreadPool , in questo modo:

 ThreadPool.QueueUserWorkItem(delegate { GenerateMainXml(); }); 

Come ha detto SLaks, EndInvoke assicura contro perdite di memoria.

BeginInvoke è ancora asincrono; considera il seguente codice:

 static void Main() { Func slowCalculator = new Func(PerformSlowCalculation); IAsyncResult slowCalculation = slowCalculator.BeginInvoke(null, null); // lots of stuff to do while slowCalculator is doing its thing Console.WriteLine("Result is {0}", slowCalculator.EndInvoke(slowCalculation)); } static double PerformSlowCalculation() { double result; // lots and lots of code return result; } 

Se questo codice fosse stato scritto senza le chiamate PerformSlowCalculation / EndInvoke , PerformSlowCalculation avrebbe dovuto terminare prima che Main potesse fare il resto delle sue “molte cose”; in questo modo, i due possono accadere contemporaneamente.

Ora, nel tuo esempio utilizzando un GenerateXmlDelegate , hai ancora bisogno di EndInvoke anche se non stai restituendo nulla. Il modo per farlo è:

 static void Main(string[] args) { GenerateXmlDelegate worker = new GenerateXmlDelegate(GenerateMainXml); IAsyncResult result = worker.BeginInvoke(GenerateXmlComplete, null); } private static void GenerateXmlComplete(IAsyncResult result) { AsyncResult realResult = result as AsyncResult; GenerateXmlDelegate worker = result.AsyncDelegate as GenerateXmlDelegate; worker.EndInvoke(); }