Why does this test fail?
The only difference between t1
and t2
, as far as I can tell, is that t1
is a Task
, and t2
is a Task<int>
. Yet for some reason t2
ends up in the Faulted
status, as opposed to the Canceled
status. Why would the behavior differ?
[Test]
public void Test_foo()
{
var t1 = Task.Run(() =>
{
throw new OperationCanceledException();
});
try
{
t1.Wait();
}
catch (AggregateException e)
{
Assert.IsTrue(t1.IsCanceled);
}
var t2 = Task.Run(() =>
{
throw new OperationCanceledException();
return 1;
});
try
{
t2.Wait();
}
catch (AggregateException e)
{
Assert.IsTrue(t2.IsCanceled); // fails, it's Faulted
}
}
The main difference between your tasks is the overload for the
Task.Run
method you're using:task1
is created withTask.Run Method (Func<Task>)
, rather thantask2
is created withTask.Run<TResult> Method (Func<TResult>)
. This overloads do create task with a little bit difference:task1
theResult
property is set toSystem.Threading.Tasks.VoidTaskResult
, andCreationOptions
is set toNone
,task2
theCreationOptions
is set toDenyChildAttach
, and the result is adefault(int)
, which is0
.When you are waiting the
task2
, theResult
property isn't being set to real value, because the exception is thrown. According MSDN:So, here we can find the reason for this behavior - the exception is treated like a normal exception because of the token mismatch. This is strange, because the token is definitely the same (I've checked that in Debug, the hash code is equal,
Equals
method and double equals operator returnstrue
), but the comparison still returnsfalse
. So, the solution for your case is explicit usage of the cancellation tokens, something like this (I've added theThread.Sleep
to avoid the race condition):Another quote from MSDN:
As you can see, the preffered way is working predictably, the direct exception throw does not. Please also note that in case of usage
task
is created withDenyChildAttach
too, and doesn't have aResult
property, so there is some difference in constructors, which you've faced with.Hope this helps.