Noc*_*ceo 1 c# wpf multithreading
我在单独的线程中运行一些代码,这可能会引发异常(毕竟,代码倾向于这样做)。该线程将从主线程(GUI)派生,因此最终必须在此处理异常(例如,设置错误消息文本块)。我有两种解决方案,但都不允许在GUI线程中直接捕获异常。
注:我不能用这样的东西 Task 和 BackgroundWorker (至少不开箱),因为我需要能够改变 ApartmentState 线程的。
这是我想要的:
var thread = new Thread(() =>
{
// Code which can throw exceptions
});
try
{
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
MethodThatAwaitsThread(thread);
}
catch
{
// Exception handling in the GUI thread
}
Run Code Online (Sandbox Code Playgroud)
这是行不通的,因为异常永远不会离开线程。我知道它不能随时离开线程,但是我可以等待线程结束然后捕获它。
这是我当前的解决方案,它利用Dispatcher与GUI线程进行通信:
var thread = new Thread(() =>
{
try
{
// Code which can throw exceptions
Dispatcher.Invoke(UpdateGuiAsSuccess);
}
catch (Exception ex)
{
Dispatcher.Invoke(UpdateGuiAsError);
}
}
Run Code Online (Sandbox Code Playgroud)
另一种解决方案是将Exceptionin 存储在对象中,然后在之后显式检查它。但这冒着人们忘记检查异常的风险:
Exception ex = null;
var thread = new Thread(() =>
{
try
{
// Code which can throw exceptions
}
catch (Exception threadEx)
{
ex = threadEx;
}
}
if (ex != null)
{
UpdateGuiAsError();
}
else
{
UpdateGuiAsSuccess();
}
Run Code Online (Sandbox Code Playgroud)
无论如何,一旦工作线程死亡,我是否可以在GUI线程中重新抛出该错误?
您可以使用TaskSTA线程(我认为这是您想要的)。
为此,您可以编写一些帮助程序方法以在已设置为STA的线程上启动任务:
public static class STATask
{
/// <summary>
/// Similar to Task.Run(), except this creates a task that runs on a thread
/// in an STA apartment rather than Task's MTA apartment.
/// </summary>
/// <typeparam name="TResult">The return type of the task.</typeparam>
/// <param name="function">The work to execute asynchronously.</param>
/// <returns>A task object that represents the work queued to execute on an STA thread.</returns>
[NotNull] public static Task<TResult> Run<TResult>([NotNull] Func<TResult> function)
{
var tcs = new TaskCompletionSource<TResult>();
var thread = new Thread(() =>
{
try
{
tcs.SetResult(function());
}
catch (Exception e)
{
tcs.SetException(e);
}
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
return tcs.Task;
}
/// <summary>
/// Similar to Task.Run(), except this creates a task that runs on a thread
/// in an STA apartment rather than Task's MTA apartment.
/// </summary>
/// <param name="action">The work to execute asynchronously.</param>
/// <returns>A task object that represents the work queued to execute on an STA thread.</returns>
[NotNull] public static Task Run([NotNull] Action action)
{
var tcs = new TaskCompletionSource<object>(); // Return type is irrelevant for an Action.
var thread = new Thread(() =>
{
try
{
action();
tcs.SetResult(null); // Irrelevant.
}
catch (Exception e)
{
tcs.SetException(e);
}
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
return tcs.Task;
}
}
Run Code Online (Sandbox Code Playgroud)
一旦有了它,就可以轻松地创建STA任务,然后用于.ContinueWith()处理任务中引发的异常,或用于await捕获异常。
(注意:[NotNull]来自Resharper注释-如果不使用Resharper,请将其删除。)
| 归档时间: |
|
| 查看次数: |
52 次 |
| 最近记录: |