加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – BackgroundWorker.RunWorkCompleted – 无法重新抛出异常

发布时间:2020-12-15 21:42:12 所属栏目:百科 来源:网络整理
导读:我正在为WCF调用(使用BackgroundWorker)编写某种包装器,以便在调用正在进行时保持GUI不冻结.它主要是按预期工作,但是当WCF调用抛出异常时,我遇到了BackgroundWorker的问题.如果在DoWork中发生异常,我可以在RunWorkCompleted中检测到它,但是将其重新抛出到GUI
我正在为WCF调用(使用BackgroundWorker)编写某种包装器,以便在调用正在进行时保持GUI不冻结.它主要是按预期工作,但是当WCF调用抛出异常时,我遇到了BackgroundWorker的问题.如果在DoWork中发生异常,我可以在RunWorkCompleted中检测到它,但是将其重新抛出到GUI不起作用.我已经读了很多线程,人们提到这应该有效.

包装器的代码(注意WCF调用由抛出的异常表示):

private void GetSomething(Action<IEnumerable<int>> completedAction)
{
    BackgroundWorker b = new BackgroundWorker();

    b.DoWork += (s,evt) => { throw new Exception(); evt.Result = new List<int> { 1,2,3 }; };

    b.RunWorkerCompleted += (s,evt) =>
    {
        if (evt.Error == null && completedAction != null)
        {
           completedAction((IEnumerable<int>)evt.Result);
        }
        else if(evt.Error != null)
        {
           throw evt.Error;
        }
    };

    b.RunWorkerAsync();
}

在Windows窗体中调用代码:

private void button3_Click(object sender,EventArgs e)
{
    try
    {
        GetSomething(list =>
        {
           foreach (int i in list)
           {
              listView1.Items.Add(new ListViewItem(i.ToString()));
           }
        });
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

在调试时,我得到:

  1. “Exception of type ‘System.Exception’ was thrown” in DoWork
  2. “Exception of type ‘System.Exception’ was thrown” at throw evt.Error
  3. “TargetInvocationException was unhandled” at Application.Run(new Form1()) in the Main method

我究竟做错了什么?我想在Windows窗体中捕获异常.

解决方法

事件b.RunWorkerCompleted是您应该进行错误处理的地方.您可以传递一个Action< Exception>做错误处理就像

private void GetSomething(Action<IEnumerable<int>> completedAction,Action<Exception> exceptionAction)
{
    BackgroundWorker b = new BackgroundWorker();

    b.DoWork += (s,evt) =>
    {
        if (evt.Error == null && completedAction != null)
            completedAction((IEnumerable<int>)evt.Result);
        else if(evt.Error != null)
            exceptionAction(evt.Error);
    };

    b.RunWorkerAsync();
}

然而,这往往会变得丑陋.如果您使用.Net 4或4.5,则可以使用“任务”.任务< TResult>是为了这种情况而创建的:

Task<IEnumerable<int>> GetSomething()
{
    return Task.Factory.StartNew(() => { 
        Thread.Sleep(2000);
        throw new Exception(); 
        return (new List<int> { 1,3 }).AsEnumerable(); 
        });
}

任务基本上是一个信号构造

> a.结果财产
> .Exception属性
> a .ContinueWith()方法

在ContinueWith()中,您可以检查Task是否处于故障状态(Exception被抛出).

你可以像使用它一样

private void button3_Click(object sender,EventArgs e)
    {
        GetSomething()
            .ContinueWith(task =>
                {
                    if (task.IsCanceled)
                    {
                    }
                    else if (task.IsFaulted)
                    {
                        var ex = task.Exception.InnerException;
                        MessageBox.Show(ex.Message);
                    }
                    else if (task.IsCompleted)
                    {
                        var list = task.Result;
                        foreach (int i in list)
                        {
                            listView1.Items.Add(new ListViewItem(i.ToString()));
                        }
                    }
                });
    }

如果您使用.Net 4.5和C#5(您需要VS2012或VS2010和Async CTP),您甚至可以使用异步并等待

private async void button3_Click(object sender,EventArgs e)
    {
        try
        {
            var list = await GetSomething();
            foreach (int i in list)
            {
                listView1.Items.Add(new ListViewItem(i.ToString()));
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }
    }

……所有的魔力都是由编译器完成的.请注意,您可以像以前一样使用try catch.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读