-1

I have the following code in the

private void Button_Click(object sender, EventArgs e)
{
    try
    {
        Task.Run(async () => await Presenter.Search());
    }
    catch (Exception ex)
    {
        LabelMessage.Text = "Error:....";
    }
}

The function Presenter.Search() may get exceptions in some cases and I want to show an error message. However, the exception is not raised? I can only see it in the Visual studio debugger.

ca9163d9
  • 27,283
  • 64
  • 210
  • 413
  • 2
    It runs async, you're not `await`ing it, how is the `Task.Run` supposed to throw a exception which happens somewhen in the future? – tkausl Nov 16 '18 at 18:16

2 Answers2

4

Really this should be written like so:

private async void Button_Click(object sender, EventArgs e)
{
    try
    {
        await Presenter.Search();
    }
    catch (Exception ex)
    {
        LabelMessage.Text = "Error:....";
    }
}

Now the call is awaited and the exception will be handled correctly. Note that you shouldn't typically use async void for the reasons listed here, but in the case of UI event handlers it's the recommended approach.

ProgrammingLlama
  • 36,677
  • 7
  • 67
  • 86
  • My code is more complex than that. The code is actually kicked up by a timer in constructor. I think I will need to post a new question – ca9163d9 Nov 16 '18 at 18:21
  • 2
    @ca9163d9 I think so too. Your question needs to accurately match what you need to do, as well as describe the circumstances involved (the timer). –  Nov 16 '18 at 18:24
2

First of all, if Presenter.Search already returns a Task you should consider to make the event handler async and simply put

await Presenter.Search();

in the try-catch block.

The reason of Task.Run(Func<Task>) overload exists is that you can force an already existing Task to be scheduled for execution on a pool thread. This case can be justified in very rare cases as normally you should rely on the internal implementation of the Task returning methods. But if you know that an async method does not use threads (for example, just returns a Task, which will be completed on a specific event) and you are confident enough about forcing the execution on a pool thread you can do it this way. But also in this case you should await the external task; otherwise, the call is fire-and-forget and you will not catch anything:

await Task.Run(() => Presenter.Search());

Please note that I omitted the inner async-await:

await Task.Run(async () => await Presenter.Search());

This would also work and is functionally equivalent to the previous version but adds a needless inner state machine to the chain of tasks to execute.

TL;DR: Without knowing any further details await Presenter.Search(); seems to be the better solution but also await Task.Run(() => Presenter.Search()); can be justified if you know what you are doing.

György Kőszeg
  • 17,093
  • 6
  • 37
  • 65