Arvis
Arvis

Reputation: 8363

Exception handling outside of Task

Just noticed strange thing: to catch exception in caller from new Task, lambda MUST be marked as async!? Is it really necessary even if delegate has no await operators at all?

    try
    {
        //Task.Run(() =>      // exception is not caught!
        Task.Run(async () =>  // unnecessary async!?!   
        {
            throw new Exception("Exception in Task");
        }).Wait();
    }
    catch (Exception ex)
    {
        res = ex.Message;
    }

Why there is neccesary for async operator? All documentation i can find tells that delegate must not return Void and Task must be awaited for exception to propogate up to caller.

Added full code:

class Program
{
    static void Main(string[] args)
    {
        var p = new Program();
        p.Run();
    }

public void Run()
{
    string result;

    try
    {
        result = OnSomeEvent((s, ea) => RunSomeTask());
    }
    catch (Exception ex) // Try to catch unhandled exceptions here!
    {
        result = ex.Message;
    }

    Console.WriteLine(result);
    Console.ReadKey();
}

// Some other Framework bult-in event (can not change signature)
public string OnSomeEvent(EventHandler e)
{
    e.Invoke(null, new EventArgs());
    return "OK";
}

private async Task RunSomeTask()
{
    await Task.Run(async () => // do not need async here!!!
    //await Task.Run(() =>     // caller do not catches exceptions (but must)
    {
        throw new Exception("Exception in Task1");
    });
}
}

So the qestion is how to catche ex. without asyn keyword???

Upvotes: 1

Views: 448

Answers (2)

Stephen Cleary
Stephen Cleary

Reputation: 457207

Methods that return Task - such as Task.Run or async methods - will place any exceptions on that returned Task. It's up to you to observe that exception somehow. Normally this is done with await, like this:

await Task.Run(() => { throw ... });

In your case, the problem is in this line:

result = OnSomeEvent((s, ea) => RunSomeTask());

In this code, RunSomeTask is returning a Task, and that Task is never awaited. In order to observe the exception, you should await that task.

Upvotes: 1

David
David

Reputation: 10708

When using async/await, exceptions are automatically unwrapped at the site of the await. When using a Task and .Wait(), any exception are wrapped when they come out of the Task, and thus getting information requires you to dig into the Task.Exception property, since they do not propagate up the call stack.

See https://dotnetfiddle.net/MmEXsT

Upvotes: 0

Related Questions