2012-01-05 101 views
1

我有這樣的事情:例外異步循環

void GenerateReports() { 
    foreach (var employee in employees) { 
     GenerateReport(employee); 
    } 
} 

GenerateReport需要很長時間,我不希望阻止我的UI線程,所以我運行一個單獨的線程此方法。

但是,GenerateReport偶爾會引發異常。我想在我的UI線程中處理每個異常,並繼續與下一個員工。如何在異步生成報告時執行此操作?如果我把GenerateReport在另一個線程,foreach循環會非常快,並在同一時間創建的所有報告:

void GenerateReports() { 
    foreach (var employee in employees) { 
     GenerateReportAsync(employee, OnDoneCallback); // returns immediately 
    } 
} 

我還是要同時創建一個報告,而是在一個單獨的線程,處理每位員工的例外情況。我怎樣才能最好地實現這一點?

+1

您是否使用.NET 4.0並且可以使用TPL? TPL可以輕鬆檢查任務中的異常。 – 2012-01-05 18:42:10

+0

我目前使用的是.NET 3.5,但我認爲如果這樣可以讓事情變得更容易,我的應用程序升級到.NET 4.0。 – Sjoerd 2012-01-05 18:46:52

+0

好的,你喜歡3.5的答案嗎?我個人發現4.0 TPL使處理異步進程變得容易很多,但是如果有令人信服的理由讓你想保持3.5的狀態,那也不錯。 – 2012-01-05 18:53:40

回答

1

如果您使用BackGround Worker進行線程化,則可以使用其BackgroundWorker.ReportProgress方法詳細信息here。發送數據返回到您的UI線程。

1

我會把你的方法,將引發錯誤的部件周圍一個try-catch,如果你希望它們交還給UI線程,創建可以傳遞一個回調方法:

void OnErrorCallback(Exception ex) 
{ 
    if(InvokeRequired) 
    { 
     //bring method execution up to the UI thread 
     this.Invoke((MethodInvoker)(()=>OnErrorCallback(ex))); 
     return; 
    } 

    //handle the exception, with access to UI components. 
} 

void GenerateReports() { 
    foreach (var employee in employees) { 
     GenerateReportAsync(employee, OnDoneCallback); // returns immediately 
    } 
} 

void GenerateReportAsync(Employee employee, AsyncCallback OnDoneCallback) 
{ 
    //Delegate.BeginInvoke takes all parameters of the delegate, plus 
    //something to call when done, PLUS a state object that can be 
    //used to monitor work in progress (null is fine too). 
    GenerateReport.BeginInvoke(employee, OnErrorCallback, OnDoneCallback, null); 
} 

void GenerateReport(Employee employee, Action<Exception> errorCallback) 
{ 
    try 
    { 
     //do your dirty work 
    } 
    catch(Exception ex) 
    { 
     //execute the delegate, which will re-execute itself on the UI 
     //thread if necessary. You're basically rethrowing the exception 
     //"sideways" to the UI thread, rather than up the call stack. 
     errorCallback(ex); 
    } 
} 
0

你可以使用後臺工人類...這樣的東西。

void GenerateReports() 
{ 
var backgroundWorker = new BackgroundWorker(); 
backgroundWorker.DoWork += ((s, e) => 
    { 
     // time consuming function 
     foreach (var employee in employees) 
      GenerateReport(employee); 
    }); 

backgroundWorker.RunWorkerCompleted += ((s, e) => 
    { 
     //do something 
    }); 

backgroundWorker.RunWorkerAsync(); 
} 

delegate void Update(Employee employee); 
static void GenerateReport(Employee employee) 
{ 
    if (this.InvokeRequired) 
    { 
     Update updaterDelegate = new Update(GenerateReport); 
     this.Invoke(updaterDelegate, new object[] { employee }); 
    } 
    else 
     GenerateReport(employee) 
}