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