Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/321.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 异步循环中的异常_C#_Winforms_Multithreading - Fatal编程技术网

C# 异步循环中的异常

C# 异步循环中的异常,c#,winforms,multithreading,C#,Winforms,Multithreading,我有这样的想法: void GenerateReports() { foreach (var employee in employees) { GenerateReport(employee); } } GenerateReport需要很长时间,我不想阻塞我的UI线程,所以我在一个单独的线程中运行这个方法 但是,GenerateReport偶尔会引发异常。我想处理UI线程中的每个异常,并继续处理下一个员工。如何在异步生成报告时做到这一点?如果我将Generate

我有这样的想法:

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
    }
}

我仍然希望一次创建一个报告,但是在一个单独的线程中,为每个员工处理一个异常。如何最好地实现这一点?

如果您使用后台工作线程,则可以使用其BackgroundWorker.ReportProgress方法详细信息。将数据发送回UI线程。

我会在方法中会抛出错误的部分放置一个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);
    }
}
void OnErrorCallback(异常示例)
{
如果(需要调用)
{
//将方法执行提升到UI线程
this.Invoke((MethodInvoker)(()=>OnErrorCallback(ex));
返回;
}
//处理异常,并访问UI组件。
}
void generatereport(){
foreach(员工中的var员工){
GenerateReportAsync(employee,OnDoneCallback);//立即返回
}
}
void GenerateReportAsync(员工-员工,AsyncCallback-OnDoneCallback)
{
//Delegate.BeginInvoke接受委托的所有参数,以及
//完成后要调用的东西,加上可以
//用于监视正在进行的工作(null也可以)。
GenerateReport.BeginInvoke(employee,OneErrorCallback,OnDoneCallback,null);
}
无效生成报告(员工,操作错误回调)
{
尝试
{
//干你的脏活
}
捕获(例外情况除外)
{
//执行委托,委托将在UI上重新执行自身
//如果需要的话,线程。你基本上是在重新引用异常
//“横向”到UI线程,而不是向上调用堆栈。
错误回调(ex);
}
}

您可以使用后台工作者类..类似这样的

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)
}

您是否在.NET4.0中并且可以使用TPL?TPL可以很容易地检查任务中的异常。我目前正在使用.NET 3.5,但我认为升级我的应用程序到.NET 4,如果这使事情变得容易。好吧,你喜欢3.5的答案呢?我个人认为4.0 TPL使处理异步进程变得更加容易,但如果有令人信服的理由让你想继续使用3.5,那也没关系。是的,我更喜欢3.5答案。GenerateReport在另一个类中吗?基本上,你可以对基思的答案稍加修改,以达到这个目的。。