Yura Zaletskyy Yura Zaletskyy - 1 month ago 12
C# Question

Why the first code displays error message immediately, but second not

Lets say we have two button clicks:

private void button2_Click(object sender, EventArgs e)
{
using (
System.Threading.Tasks.Task t = new System.Threading.Tasks.Task(() => {
throw new Exception("puzzle");

}))
{
t.Start();
}
}

private void button3_Click(object sender, EventArgs e)
{
System.Threading.Tasks.Task t = new System.Threading.Tasks.Task(() => {
throw new Exception("puzzle");

});
t.Start();
}


If to run program with those two event handlers for buttons without debugging, then button2_Click causes error message appears immediately. But button3_Click doesn't cause error message to appear immediately. I've got impression that if Task is garbage collected, then it throws exception. And if Task is not garbage collected, then exception is generated, but remains in some interesting place. I tried to find some good examples on MSDN, but wasn't very lucky.

Answer

I could see error throwing from other button handler. It will be evident to you, if you enable Just My Code in VS IDE (Tools-> Options-> Debugging-> General)

Before I explain why you could see error from button2 handler and why not from button3, it make sense to know how .NET handles Task exceptions.

To start with, both of your Task actions are throwing exception those are going unhandled by your code. When it comes to Task, any unhandled exceptions that are thrown by user code is propagated back to the calling thread in the form of AggregateException; and this exception raises only when you Wait on this Task (which case the exception) or call Result on it to get the output. In your case, you are not doing either of these and hence your exception go unnoticed. But these exceptions still hang around until tasks are garbage collected and will escalate according to .NET exception policy. TaskScheduler.UnobservedTaskException is something you need to look into if you want to override the exception escalation.

Now coming back to your handlers;

In case of button2 : You are asking to perform a deterministic destruction (using block) momentarily after starting the task. This means, your task might be possibly in WaitingToRun, WaitingForActivation, RunningRunning etc state. According to MSDN, a task may only be disposed if it is in a completion state (RanToCompletion, Faulted or Canceled). Having said this, exception might not be apparent in all case since it is depend on state of your Task and the moment at which deterministic destruction kicks in.

In case of button3: You are not disposing the Task by yourself and leaving it for garbage collector to perform this for you. This is why you can't see any exception. I hope you will be clear on how the exception is handled for you.

MSDN has detailed explanation on how TASK exceptions are handled in .NET and its covers multiple scenarios.

Comments