2012-01-05 123 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) 
}