2

My Console App uses System.ComponentModel.BackgroundWorker for threading purposes:

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

As you can see that I am passing "worker" as an argument inside RunWorkerAsync.

What I am trying to achieve is that if there is an exception inside ReportStatus method I need the same "worker" object so that I can perform some operation (Call a service to notify that workers exception)

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

In my exception block (I am not sure if this is the correct way!) I am assigning the worker to the Result so that I can get the same worker back when the RunWorkerCompleted method (backgroundWorker1_RunWorkerCompleted) is executed :

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

3 回答 3

2

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

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

如果您将工作对象传递给BackgroundWorker,为什么不只使用您在异常处理程序中传入的内容,该异常处理程序包装对测试的调用Result或在测试块中Error?例如:

        if (e.Error != null)
        {
            worker.DoSomething(); // no access of Result
        }
于 2012-09-12T20:54:02.890 回答
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);
    }
}

在这种情况下,您将能够检索异常的 Worker,将 Error 转换为 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!
    }
}
于 2012-09-12T22:16:32.163 回答
0

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

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

于 2012-09-13T01:11:06.653 回答