C# 任务。等待引发异常
主要是作为这个问题的后续,我提出了一些代码,如果我不让任务等待,这些代码可以工作,但如果我让任务等待,则会失败 有人能解释为什么吗 例外情况:C# 任务。等待引发异常,c#,unit-testing,parallel-processing,task-parallel-library,async-await,C#,Unit Testing,Parallel Processing,Task Parallel Library,Async Await,主要是作为这个问题的后续,我提出了一些代码,如果我不让任务等待,这些代码可以工作,但如果我让任务等待,则会失败 有人能解释为什么吗 例外情况: private class MockSynchContext : SynchronizationContext{} [Test] public void OnSuccessFullComplete_ExpectedResultIsReturned_Wait() { var mc = new MockSynchContext(); Syn
private class MockSynchContext : SynchronizationContext{}
[Test]
public void OnSuccessFullComplete_ExpectedResultIsReturned_Wait()
{
var mc = new MockSynchContext();
SynchronizationContext.SetSynchronizationContext(mc);
Assert.That(SynchronizationContext.Current, Is.EqualTo(mc));
Assert.DoesNotThrow(() => TaskScheduler.FromCurrentSynchronizationContext());
var task = Task.Factory.StartNew(() => _startBackgroundTask(false));
task.Wait(2000);
_actualResult = 42;
}
private void _startBackgroundTask(bool causeError)
{
_cancellationTokenSource = new CancellationTokenSource();
var cancellationToken = _cancellationTokenSource.Token;
_progressReporter = new ProgressReporter();
var task = Task.Factory.StartNew(() =>
{
for (var i = 0; i != 100; ++i) {
// Check for cancellation
cancellationToken.ThrowIfCancellationRequested();
Thread.Sleep(30); // Do some work.
// Report progress of the work.
_progressReporter.ReportProgress(
() =>
{
// Note: code passed to "ReportProgress" can access UI elements freely.
_currentProgress = i;
});
}
// After all that work, cause the error if requested.
if (causeError) {
throw new InvalidOperationException("Oops...");
}
// The answer, at last!
return 42;
},
cancellationToken);
// ProgressReporter can be used to report successful completion,
// cancelation, or failure to the UI thread.
_progressReporter.RegisterContinuation(task, () =>
{
// Update UI to reflect completion.
_currentProgress = 100;
// Display results.
if (task.Exception != null)
_actualErrorMessage = task.Exception.ToString();
else if (task.IsCanceled)
_wasCancelled = true;
else
_actualResult = task.Result;
// Reset UI.
_whenCompleted();
});
}
当代码击中Stephen Cleary在其博客上编写的实用程序类的构造函数时,我遇到了这个错误
SuT:
private class MockSynchContext : SynchronizationContext{}
[Test]
public void OnSuccessFullComplete_ExpectedResultIsReturned_Wait()
{
var mc = new MockSynchContext();
SynchronizationContext.SetSynchronizationContext(mc);
Assert.That(SynchronizationContext.Current, Is.EqualTo(mc));
Assert.DoesNotThrow(() => TaskScheduler.FromCurrentSynchronizationContext());
var task = Task.Factory.StartNew(() => _startBackgroundTask(false));
task.Wait(2000);
_actualResult = 42;
}
private void _startBackgroundTask(bool causeError)
{
_cancellationTokenSource = new CancellationTokenSource();
var cancellationToken = _cancellationTokenSource.Token;
_progressReporter = new ProgressReporter();
var task = Task.Factory.StartNew(() =>
{
for (var i = 0; i != 100; ++i) {
// Check for cancellation
cancellationToken.ThrowIfCancellationRequested();
Thread.Sleep(30); // Do some work.
// Report progress of the work.
_progressReporter.ReportProgress(
() =>
{
// Note: code passed to "ReportProgress" can access UI elements freely.
_currentProgress = i;
});
}
// After all that work, cause the error if requested.
if (causeError) {
throw new InvalidOperationException("Oops...");
}
// The answer, at last!
return 42;
},
cancellationToken);
// ProgressReporter can be used to report successful completion,
// cancelation, or failure to the UI thread.
_progressReporter.RegisterContinuation(task, () =>
{
// Update UI to reflect completion.
_currentProgress = 100;
// Display results.
if (task.Exception != null)
_actualErrorMessage = task.Exception.ToString();
else if (task.IsCanceled)
_wasCancelled = true;
else
_actualResult = task.Result;
// Reset UI.
_whenCompleted();
});
}
只是想澄清一下:如果我注释掉这个任务。等等,那个测试实际上成功了。为什么呢
额外积分:
private class MockSynchContext : SynchronizationContext{}
[Test]
public void OnSuccessFullComplete_ExpectedResultIsReturned_Wait()
{
var mc = new MockSynchContext();
SynchronizationContext.SetSynchronizationContext(mc);
Assert.That(SynchronizationContext.Current, Is.EqualTo(mc));
Assert.DoesNotThrow(() => TaskScheduler.FromCurrentSynchronizationContext());
var task = Task.Factory.StartNew(() => _startBackgroundTask(false));
task.Wait(2000);
_actualResult = 42;
}
private void _startBackgroundTask(bool causeError)
{
_cancellationTokenSource = new CancellationTokenSource();
var cancellationToken = _cancellationTokenSource.Token;
_progressReporter = new ProgressReporter();
var task = Task.Factory.StartNew(() =>
{
for (var i = 0; i != 100; ++i) {
// Check for cancellation
cancellationToken.ThrowIfCancellationRequested();
Thread.Sleep(30); // Do some work.
// Report progress of the work.
_progressReporter.ReportProgress(
() =>
{
// Note: code passed to "ReportProgress" can access UI elements freely.
_currentProgress = i;
});
}
// After all that work, cause the error if requested.
if (causeError) {
throw new InvalidOperationException("Oops...");
}
// The answer, at last!
return 42;
},
cancellationToken);
// ProgressReporter can be used to report successful completion,
// cancelation, or failure to the UI thread.
_progressReporter.RegisterContinuation(task, () =>
{
// Update UI to reflect completion.
_currentProgress = 100;
// Display results.
if (task.Exception != null)
_actualErrorMessage = task.Exception.ToString();
else if (task.IsCanceled)
_wasCancelled = true;
else
_actualResult = task.Result;
// Reset UI.
_whenCompleted();
});
}
我知道这在技术上是另一个问题,但重复所有这些似乎是一种耻辱,因此:
为什么我的MockSynchContext在测试中没有在TaskScheduler.FromCurrentSynchronizationContext()上引发异常,但在第二个任务中却引发了异常?更重要的是,是否有一种方法可以传递上下文,以便我能够正确地进行测试
“如果我将任务注释掉。等等,该测试实际上成功了。为什么?”
在您实际检查任务(通过“等待”、“值”、“处置”等)之前,任务不会报告任务本身中发生的异常。然后,它重新调用异常。在真正的应用程序中,GC最终会到达任务并导致应用程序崩溃 @斯蒂芬·克利里:也许你应该问问斯蒂芬我很好奇@alias的功能是否适用于所有帖子。尽管它确实提出了我在最后编辑的帖子中提到的问题,但它还是有意义的。非常感谢您对这方面的任何意见。干杯