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

C# 发生异常时将自定义对象传递给RunWorkerCompleted事件,c#,.net,multithreading,exception-handling,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

我的控制台应用程序使用
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”对象,以便执行某些操作(调用服务以通知该workers异常)

在我的异常块(我不确定这是否是正确的方法!)中,我将工作者分配给结果,以便在执行RunWorkerCompleted方法(backgroundWorker1\U RunWorkerCompleted)时可以获得相同的工作者:

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

这是因为你被抛出了异常
BackgroundWorker
将其视为未经
DoWork
处理程序处理的异常,并在获得
结果
值时将其重新抛出到另一个线程

如果您不想让它这样做,请在
DoWork
处理程序中删除捕获中的
抛出

如果您将worker对象传递到
BackgroundWorker
,为什么不使用您在异常处理程序中传递的内容来包装对
Result
的调用或在测试
错误的块中传递的内容呢?e、 g:

        if (e.Error != null)
        {
            worker.DoSomething(); // no access of Result
        }

这是因为你被抛出了异常
BackgroundWorker
将其视为未经
DoWork
处理程序处理的异常,并在获得
结果
值时将其重新抛出到另一个线程

如果您不想让它这样做,请在
DoWork
处理程序中删除捕获中的
抛出

如果您将worker对象传递到
BackgroundWorker
,为什么不使用您在异常处理程序中传递的内容来包装对
Result
的调用或在测试
错误的块中传递的内容呢?e、 g:

        if (e.Error != null)
        {
            worker.DoSomething(); // no access of Result
        }

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

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

RunWorkerCompletedEventArgs
包含一个
UserState
属性,我认为该属性应该是对传递给
RunWorkerAsync
方法的同一对象的引用。(它还应作为
参数
属性位于
DoWorkEventArgs
中。)


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

RunWorkerCompletedEventArgs
包含一个
UserState
属性,我认为该属性应该是对传递给
RunWorkerAsync
方法的同一对象的引用。(它还应作为
参数
属性位于
DoWorkEventArgs
中。)


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

如果我不清楚的话,很抱歉,但基本的问题是“backgroundWorker1_RunWorkerCompleted”当我尝试将参数转换回worker对象时,我得到一个异常:由于我正在抛出异常(使其冒泡到backgroundWorker1_RunWorkerCompleted),我得到的异常是:“操作期间发生异常,导致结果无效。检查InnerException以了解异常详细信息。“如果我不清楚,很抱歉,但基本问题是,在“backgroundWorker1\u RunWorkerCompleted”中,当我尝试将参数转换回worker对象时,我会收到一个异常:因为我正在抛出异常(它会冒泡到backgroundWorker1\u RunWorkerCompleted),所以我得到的异常是:操作期间发生异常,导致结果无效。检查InnerException以了解异常详细信息。“删除抛出确实有效,我确实可以取回worker对象,但在这种情况下,e.Error为nullYeah,如果要在结果中使用worker,请不要抛出。如果要使用Error,请抛出,并且不将结果设置为worker…那么我如何将worker对象传递给”backgroundWorker1_RunWorkerCompleted“在发生异常的情况下?”:)好吧,你只能有一个“结果”。如果你想要的结果是异常/错误,那么这就是唯一的结果。如果你想支持错误,你可以使用调用
BackgroundWorker
的类中包含的“共享”工作者对象。你描述“工作者”的方式“它不是一个“结果”,在
result
中使用时似乎不合适。我只需要在form类中编写失败代码,并在那里处理worker。创建一个自定义异常包装器(下面由@Philipp描述)是一个不错的选择!:)移除抛出确实有效,并且我确实获得了worker对象,但是在这种情况下,e.Error为null是的,如果您想在结果中使用worker,请不要抛出。如果您确实希望使用Error,throw,并且不将结果设置为worker…那么在出现异常时,如何将worker对象传递给“backgroundWorker1\u RunWorkerCompleted”?:)嗯,你只能有一个“结果”。如果您想要的结果是异常/错误,那么这是唯一的结果。如果您想支持错误,可以使用“共享”工作对象c