我在单元测试中执行以下代码:
var continueScheduler = new CurrentThreadScheduler();
var task = Task.Factory
.StartNew(() => { })
.ContinueWith(obj => { throw new Exception("Fail"); }, continueScheduler);
while (!task.IsCompleted)
{
DoEvents();
Thread.Sleep(10);
}
StartNew()
启动一个新线程,执行空操作。 CurrentThreadScheduler
然后确保在主线程上执行ContinueWith()
操作:
public class CurrentThreadScheduler : TaskScheduler
{
private readonly Dispatcher _dispatcher;
public CurrentThreadScheduler()
{
_dispatcher = Dispatcher.CurrentDispatcher;
}
protected override void QueueTask(Task task)
{
_dispatcher.BeginInvoke(new Func<bool>(() => TryExecuteTask(task)));
}
protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
{
return true;
}
protected override IEnumerable<Task> GetScheduledTasks()
{
return Enumerable.Empty<Task>();
}
}
while
循环等待任务(包括ContinueWith()
)完成。这是DoEvents()
代码:
private static void DoEvents()
{
var frame = new DispatcherFrame();
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, new DispatcherOperationCallback(ExitFrame), frame);
Dispatcher.PushFrame(frame);
}
private static object ExitFrame(object frame)
{
((DispatcherFrame)frame).Continue = false;
return null;
}
问题:
我希望在ContinueWith()
操作中抛出异常以使测试失败。问题是BeginInvoke()
中的CurrentThreadScheduler.QueueTask()
吞下了异常,我无法找到检测它的方法。
我曾尝试订阅Dispatcher.CurrentDispatcher.UnhandledException
,但事件处理程序永远不会被调用。我试图使用Invoke()
代替BeginInvoke()
,希望异常会传播,但没有成功。
毋庸置疑,此问题中的代码已经过简化,以证明我的问题。
答案 0 :(得分:1)
我的调试技巧需要改进(事情之中)。问题不是Dispatcher.BeginInvoke()
,而是我对结果的处理方式。
QueueTask
的这种实现解决了这个问题:
protected override void QueueTask(Task task)
{
var method = new Func<bool>(delegate
{
bool success = TryExecuteTask(task);
if (task.IsFaulted)
{
throw new Exception("Invoke", task.Exception);
}
return success;
});
_dispatcher.BeginInvoke(method);
}
现在,听Dispatcher.CurrentDispatcher.UnhandledException
正常工作:
Dispatcher.CurrentDispatcher.UnhandledException += OnDispatcherUnhandledException;
private void OnDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
Assert.Fail("Exception: {0}", e.Exception);
}
那就是说,我同意@Noseratio的评论,即更好的解决方案是不在单元测试代码中使用WPF Dispatcher。