1

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

Arvis
  • 8,273
  • 5
  • 33
  • 46
  • You shouldn't need to use `async` - I suspect throwing an exception breaks the delegate type inference. Try specifying the delegate type explictly. – Lee Apr 24 '15 at 13:41
  • 2
    You say *exception is not caught!* when async isn't used. But indeed it is caught. Is this your actual code? – Sriram Sakthivel Apr 24 '15 at 13:51
  • @Lee is correct. I remember reading a duplicate on this exact topic a few months ago. Throwing a exception changes the return type of the anonymous delegate. – Scott Chamberlain Apr 24 '15 at 14:00
  • @SriramSakthivel, updated actual code. – Arvis Apr 24 '15 at 14:40
  • 1
    What happens in both the cases? What do you mean by works? Instead of saying works, can you tell what behavior you're observing in both the cases? – Sriram Sakthivel Apr 24 '15 at 14:54
  • If throwing is the *only* way out of the lambda passed to `Task.Run`, the [lambda is indeed inferred](http://stackoverflow.com/a/24359762/1768303) as `Func` rather than `Action`. But the exception in the your first code fragment still does get caught. – noseratio Apr 24 '15 at 23:36
  • arghh... if only someone pointed me to this thread: http://stackoverflow.com/questions/13022162/c-sharp-task-exception-not-being-caught :) – Arvis Apr 27 '15 at 14:51

2 Answers2

1

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.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • where did you suggest to put this 'await' operator? Becouse edit it this way `result = OnSomeEvent(async (s, ea) => await RunSomeTask());` do not catch ex. either, it becames lambda what returns 'void'. – Arvis Apr 27 '15 at 12:48
  • @Arvis: You have to rethink your solution. What you're trying to do right now is sync-over-async, a well-known anti-pattern. You'll have to either make your code fully asynchronous, or save the task somewhere and react to it at a later time. – Stephen Cleary Apr 27 '15 at 13:37
0

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

David
  • 10,458
  • 1
  • 28
  • 40