Exception handling outside of Task

2020-03-31 04:57发布

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???

2条回答
Evening l夕情丶
2楼-- · 2020-03-31 05:17

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

查看更多
霸刀☆藐视天下
3楼-- · 2020-03-31 05:23

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.

查看更多
登录 后发表回答