在发生异常时将自定义对象传递给RunWorkerCompleted事件

时间:2012-09-12 20:31:15

标签: c# .net multithreading exception-handling

我的控制台应用使用System.ComponentModel.BackgroundWorker进行线程处理:

System.ComponentModel.BackgroundWorker backgroundWorker = new System.ComponentModel.BackgroundWorker();

backgroundWorker.DoWork += (sender, e) =>
     ReportStatus(worker, status, result, e);
backgroundWorker.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);
backgroundWorker.RunWorkerAsync(worker);

正如您所看到的,我在RunWorkerAsync中传递“worker”作为参数。

我想要实现的是,如果ReportStatus方法中有异常,我需要相同的“worker”对象,以便我可以执行一些操作(调用服务来通知工作者异常)

private void ReportStatus(Worker worker, Status status, WorkResult result,System.ComponentModel.DoWorkEventArgs arg)
{
    var proxy = new PreparationServiceProxy(new NetTcpBinding(), new EndpointAddress(PreparationEngineState.ServiceAddress));
    try
    {
        proxy.ReportStatus(worker, status, result);
        proxy.Close();
    }
    catch (Exception)
    {
        arg.Result = worker;
        proxy.Abort();
        throw;
    }
}

在我的异常块中(我不确定这是否是正确的方法!)我将worker分配给Result,以便在执行RunWorkerCompleted方法(backgroundWorker1_RunWorkerCompleted)时可以返回同一个worker:

private void backgroundWorker1_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
{

    if (e.Error != null)
    {
        Worker worker = e.Result as Worker; // At this point I get an exception!
    }
}

3 个答案:

答案 0 :(得分:2)

这是因为你重新抛出异常。 BackgroundWorkerDoWork处理程序未处理的异常视为异常,并在获得Result值时将其重新抛回另一个线程。

如果您不希望这样做,请删除throw处理程序中catch中的DoWork

如果你将worker对象传递给BackgroundWorker,为什么不使用你在包含对Result的调用的异常处理程序中或在测试{{1}的块中传入的内容}}? e.g:

Error

答案 1 :(得分:2)

如果发生错误,.NET不会认为异步操作可能会产生一些结果。这就是为什么你会以其他方式传递它。

我建议实现自定义异常类:

public class WorkerException:ApplicationException
{
    public WorkerException(Worker worker,Exception innerException):base(null,innerException)
    { Worker = worker; }

    public Worker Worker
    {
        get;
        set;
    }
}

相应地包装你的异常:

private void ReportStatus(Worker worker, Status status, WorkResult result,System.ComponentModel.DoWorkEventArgs arg)
{
    var proxy = new PreparationServiceProxy(new NetTcpBinding(), new EndpointAddress(PreparationEngineState.ServiceAddress));
    try
    {
        proxy.ReportStatus(worker, status, result);
        proxy.Close();
    }
    catch (Exception exception)
    {
        arg.Result = worker;
        proxy.Abort();
        throw new WorkerException(worker,exception);
    }
}

在这种情况下,您将能够检索异常工作者,将错误强制转换为WorkerException:

private void backgroundWorker1_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
{

    if (e.Error is WorkerException)
    {
        Worker worker = ((WorkerException)e.Error).Worker; // At this point I get an exception!
    }
}

答案 2 :(得分:0)

RunWorkerCompletedEventArgs包含UserState属性,我认为该属性应该是您传递给RunWorkerAsync方法的同一对象的引用。 (它也应该在DoWorkEventArgs中作为Argument属性。)

您需要进行试验以确认此UserState是正确的对象(强制转换为as Worker),并且即使DoWork处理程序引发异常,它也是有效的,但是我认为这可能就是你要找的东西。