2009-12-09 4 views
2

Я следующий делегатИспользование делегатов в C# Асинхронный

delegate void UpdateFileDelegate(long maxFileID); 

То, что я звоню из приложения WinForms, как так

UpdateFileDelegate FD = new UpdateFileDelegate(ClassInstance.UpdateFile); 
FD.BeginInvoke(longIDNumber,null,null); 

Она работает асинхронно, но вопрос у меня есть, как я могу сказать когда метод выполняется, поэтому я могу сообщить конечному пользователю?

Обновление: В соответствии с рекомендациями нижеприведенный код выполняет трюк. Также этот article помог мне понять, что мой код действительно делает.

delegate void UpdateFileDelegate(long maxFileID); 
UpdateFileDelegate FB = new UpdateFileDelegate(ClassInstance.UpdateFile); 
AsyncCallback callback = new AsyncCallback(this.CallBackMethod); 
IAsyncResult result = FB.BeginInvoke(longIDNumber); 

private void CallBackMethod(IAsyncResult result) 
    { 
    AsyncResult delegateResult = (AsyncResult)result; 

    UpdateFileDelegate fd = (UpdateFileDelegate)delegateResult.AsyncDelegate; 
    fd.EndInvoke(result); 
    MessageBox.Show("All Done!"); 
    } 

ответ

7

См Calling Synchronous Methods Asynchronously

The BeginInvoke возвращает IAsyncResult, что позволяет несколько различных способов, чтобы быть в курсе, когда это делается, например, с помощью его метода AsyncWaitHandle.WaitOne(). Это зависит от того, что вы делаете в это время.

Или вы можете передать делегат для метода обратного вызова до BeginInvoke. Это, возможно, самая мощная стратегия, но иногда это слишком много.

7

Вызов EndInvoke по возвращенной ссылке IAsyncResult очень важен. Это единственный способ узнать, завершился ли запуск цели делегатом без каких-либо исключений. Если вы этого не сделаете, такое исключение попадет в бит-ведро, и ваша программа будет тихо работать неправильно. Вы можете вызвать EndInvoke либо в том же потоке, который называется BeginInvoke(), либо вы можете сделать это в обратном вызове. Призывать его к одной и той же теме редко полезно, вы почти всегда теряете преимущества асинхронного выполнения. Некоторые примеры кода, который демонстрирует, как и подчеркивает обработку исключений:

using System; 
using System.Runtime.Remoting.Messaging; 

class Program { 
    static void Main(string[] args) { 
    new Program().Run(); 
    Console.ReadLine(); 
    } 
    void Run() { 
    Action example = new Action(threaded); 
    IAsyncResult ia = example.BeginInvoke(new AsyncCallback(completed), null); 
    // Option #1: 
    /* 
    ia.AsyncWaitHandle.WaitOne(); 
    try { 
     example.EndInvoke(ia); 
    } 
    catch (ApplicationException ex) { 
     Console.WriteLine(ex.Message); 
    } 
    */ 
    } 

    void threaded() { 
    throw new ApplicationException("Kaboom"); 
    } 

    void completed(IAsyncResult ar) { 
    // Option #2: 
    Action example = (ar as AsyncResult).AsyncDelegate as Action; 
    try { 
     example.EndInvoke(ar); 
    } 
    catch (ApplicationException ex) { 
     Console.WriteLine(ex.Message); 
    } 
    } 
} 

Вы не должны использовать TRY блок в завершении обратного вызова, если вы не ожидаете код бросать исключения. Это гарантирует, что ваша программа прекратится, когда это произойдет.

+0

Каков правильный шаблон, если код решает, что не будет заботиться о том, что происходит с асинхронной задачей (например, поскольку пользователь нажал «отменить»), но запрос «отменить» не сразу реагирует? Просто договоритесь, чтобы его обратный вызов вызывал «EndInvoke» и умирал, а затем отказывался от него (вычисление обратного вызова будет поддерживаться до тех пор, пока задача не завершится или не обработает запрос отмены, после чего обратный вызов выполнит и очистит «IAsyncResult»? – supercat

Смежные вопросы