Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Tasks - Why a noop line is needed in this case

I am reading the source code of Interactive Extensions and have found a line that I cannot understand:

public static Task<bool> UsingEnumerator(this Task<bool> task, IDisposable disposable)
{
    task.ContinueWith(t =>
    {
        if (t.IsFaulted)
        {
            var ignored = t.Exception; // don't remove!
        }

        if (t.IsFaulted || t.IsCanceled || !t.Result)
            disposable.Dispose();
    }, TaskContinuationOptions.ExecuteSynchronously);

    return task;
}

I also do not see any relevant remarks in the docs for IsFaulted or Exception properties.

Why this line var ignored = t.Exception; // don't remove! is needed in this context?

A related question: I thought that such lines are optimized away in the Release mode, but given the comment and intent here that is not the case (if the code is correct). So why does this line stay in the Release mode?

like image 424
V.B. Avatar asked May 15 '15 16:05

V.B.


1 Answers

That line is the difference between an observed exception and an unobserved one.

In .Net 4.0 a task with an unobserved exception will throw an UnobservedTaskException and tear down the entire application:

"If you do not wait on a task that propagates an exception, or access its Exception property, the exception is escalated according to the .NET exception policy when the task is garbage-collected."

From Exception Handling (Task Parallel Library)

That was changed in .Net 4.5 with async-await, although you can get the old behavior back using the app.config (<ThrowUnobservedTaskExceptions enabled="true"/>).

There's also an event (TaskScheduler.UnobservedTaskException) that allows you to handle such faulted tasks before the application crashes. That event is still being raised in .Net 4.5 and above.

like image 181
i3arnon Avatar answered Nov 04 '22 12:11

i3arnon