The reason why it happens if you don't
await Task.Yield is that the code is executed synchronously on the same thread as the caller so it's like not being
async at all.
await, the continuation will be queued on a
ThreadPool thread which is a managed thread and behaves differently.
Since internally is caught and re-thrown from a different thread than the current, it doesn't preserve it's nature of "special application killing" exception in the shifting logic.
In addition, if it was to re-throw it, you wouldn't even been able to
Thread.ResetAbort() as it works on the current thread and will not act on the one that actually aborted.
MSDN documentation explains this, too here:
If any of these exceptions are unhandled in threads created by the
common language runtime, the exception terminates the thread, but the
common language runtime does not allow the exception to proceed
If these exceptions are unhandled in the main thread, or in threads
that entered the runtime from unmanaged code, they proceed normally,
resulting in termination of the application.
My guess on the rationale behind this is:
ThreadAbortException is re-thrown to avoid stubborn threads to try and stay alive when they shouldn't, but letting it flow and kill also other different threads would probably be quite a bad idea and cause unexpected behaviour.