I\'m digging into the async-await mechanism and observed the throwing of a TaskCanceledException that I can\'t explain yet.
In the sample b
The reason Task.Run(() => null) returns a canceled task rests in overload resolution. The compiler chooses static Task Run(Func and not static Task as one may expect. It acts as if you're calling an async delegate, which in this case you're not. That results in Task.Run "unwrapping" your return value (null) as a task which in turn would cancel the task.
The specific code responsible for that is in the ProcessInnerTask private method in the UnwrapPromise
private void ProcessInnerTask(Task task)
{
// If the inner task is null, the proxy should be canceled.
if (task == null)
{
TrySetCanceled(default(CancellationToken));
_state = STATE_DONE; // ... and record that we are done
}
// ...
}
You can easily tell the compiler not to do that by telling the compiler you are not returning a Task:
var result = await Task.Run(() => (object)null); // Will not throw an exception. result will be null
The difference between the two methods is that in TestAsyncExceptionOnlyInTheOutputWindow you don't await the faulted task and so the exception stored in the task is never rethrown.
You can make the debugger break in both methods by checking the thrown column on Common Language Runtime Exceptions in your settings (Debug => Exceptions):
