我有一个必须作为 STA 运行的函数,并且我想将其异常传播到调用线程。这是:
public void ExceptionBePropagatedThroughHere()
{
Thread thread = new Thread(TheSTAThread);
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
thread.Join();
}
public void MainFunction()
{
try
{
ExceptionBePropagatedThroughHere();
}
catch(Exception e)
{
//will not hit here
}
}
此处不能选择将 STA 属性放在“MainFunction”上。 我注意到如果我使用任务,尝试捕获任务连接会将异常传播到调用线程,但是我无法指定以 STA 方式运行任务。
问题是如何将作为 STA 运行的异常传播到上例中的“MainFunction”?
提前致谢。
我遵循了 Hans 的建议,解决方案如下所示,不需要触发任何事件。
private Exception _exception;
public void ExceptionBePropagatedThroughHere()
{
Thread thread = new Thread(TheSTAThread);Thread thread = new Thread(TheSTAThread);
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
thread.Join();
if(_exception != null)
throw new Exception("STA thread failed", _exception);
}
private void TheSTAThread()
{
try
{
//do the stuff
}
catch (Exception ex)
{
_exception = ex;
}
}
public void MainFunction()
{
try
{
ExceptionBePropagatedThroughHere();
}
catch(Exception e)
{
//will not hit here
}
}
在等待期间,您需要保持消息泵的启动和运行。 Thread.Join 不是您可以使用的选项,因为它会阻塞您的线程,直到另一个线程终止。 一个非常简单的消息泵是创建两个名为 StaThreadExited 和 StaThreadExceptionEvent 的事件。您可以对事件数组使用 WaitHandle.WaitAny。如果这是一个异常事件,您可以从例如获取它。共享变量并将其重新抛出到您自己的线程中。我什至前段时间在这里发布了代码。
你的, 阿洛伊斯·克劳斯
线程是 STA 还是 MTA 并不重要。其中未捕获的异常将使您的应用程序崩溃。您不能将其扔到创建行为不当线程的线程,除非您设计一种手动执行此操作的方法:例如捕获,将其存储在某处,并通知主线程有错误
这是一个老问题,但我想我会尝试改进建议的解决方案。 C# 已经具有在线程之间传输异常和结果的便捷机制。这就是所谓的
Task
。如果你需要 STA 线程,你就不能这样做 Task.Run
,但是有了像这样的助手,你可以享受与 STA 线程相同的便利:
public class StaTask {
public static Task Run(Action action) {
var tcs = new TaskCompletionSource<object>();
var thread = new Thread(() => {
try {
action();
tcs.SetResult(null);
}
catch (Exception e)
{
tcs.SetException(e);
}
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
return tcs.Task;
}
}
当然,可以通过添加通用返回类型来进一步改进。