Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why compiler does not allow using await inside catch block

Let say I have an async method:

public async Task Do()
{
    await Task.Delay(1000);
}

Another method is trying to call Do method inside catch block

public async Task DoMore()
{
    try
    {
    }
    catch (Exception)
    {
        await Do(); //compiled error.
    }
}

But this way, the compiler does not allow using await inside catch, is there any reason behind the scene why we could not use it that way?

like image 721
cuongle Avatar asked Oct 14 '12 06:10

cuongle


People also ask

Can we use await inside catch block?

C# await is a keyword. It is used to suspend execution of the method until the awaited task is complete. In C# 6.0, Microsoft added a new feature that allows us to use await inside the catch or finally block. So, we can perform asynchronous tasks while exception is occurred.

Can not await in the body of lock statement?

The await keyword in C# (. NET Async CTP) is not allowed from within a lock statement. From MSDN: An await expression cannot be used in a synchronous function, in a query expression, in the catch or finally block of an exception handling statement, in the block of a lock statement, or in an unsafe context.

How do you use await in a lock?

The semantics of "await lock" would be: await a SemaphoreSlim(1,1) to enter the lock, unless the thread has already entered the lock previously (i.e. allow re-entrancy on the same thread); and exit the lock at the end of the block.

What happens if we execute an asynchronous method but don't await it?

The call to the async method starts an asynchronous task. However, because no Await operator is applied, the program continues without waiting for the task to complete. In most cases, that behavior isn't expected.


1 Answers

Update

This will be supported in C# 6. It turned out that it wasn't fundamentally impossible, and the team worked out how to do so without going mad in the implementation :)

Original answer

I strongly suspect it's the same reasoning that prevents yield return from being used in a catch block.

In particular:

First off, we still have the problem that it is illegal to "goto" into the middle of the handler of a try-protected region. The only way to enter a catch block is via the "non-local goto" that is catching an exception. So once you yielded out of the catch block, the next time MoveNext was called, we’d have no way to get back into the catch block where we left off.

Second, the exception that was thrown and caught is an intrinsic part of the execution of the catch block because it can be re-thrown using the "empty throw" syntax. We have no way of preserving that state across calls to MoveNext.

Replace "yield" with "await" there, and I think you'll have your answer.

It feels like it would be an odd thing to want to do in most cases, and you should usually be able to rewrite your code fairly easily to await after the catch block - unless you were trying to await something and then throw, of course. In that case it would be a bit of a pain, I admit...

like image 100
Jon Skeet Avatar answered Oct 14 '22 10:10

Jon Skeet