Search code examples
c#exceptionplinq

Why handling TaskFactory's Exception so difficult in C#


CASE1:

        var cts = new CancellationTokenSource();
        var tf = new TaskFactory(cts.Token,
            TaskCreationOptions.AttachedToParent,
            TaskContinuationOptions.ExecuteSynchronously,
            TaskScheduler.Default);
        var childTasks = new Task[2];
        childTasks[0] = tf.StartNew(async () =>
        {

        }, TaskCreationOptions.LongRunning);
        childTasks[1] = tf.StartNew(() =>
        {
            throw new Exception("dddddd");
        });
        try
        {
            Task.WaitAll(childTasks);
        }
        catch (AggregateException ae)
        {
            foreach (var e in ae.Flatten().InnerExceptions)
            {
                Console.WriteLine(e);
            }
        }

It works.

case 2:

       ....same as 1....
        childTasks[1] = tf.StartNew(async () =>
        {
            throw new Exception("dddddd");
        });
       ....same as 1....

It doesn't work.The difference between is just the "async"

case3:

            childTasks[1] = tf.StartNew( () =>
            {
                throw new Exception("dd");
                //await b();
            }).ContinueWith((t) => { Console.WriteLine(t.Exception); }, TaskContinuationOptions.OnlyOnFaulted);

it works.

case 4:

            childTasks[1] = tf.StartNew(async () =>
            {
                //throw new Exception("dd");
                await b();
            });
            try
            {
                Task.WaitAll(childTasks);
            }
            catch (AggregateException ae)
            {
                foreach (var e in ae.Flatten().InnerExceptions)
                {
                    Console.WriteLine(e);
                }
            }
    private static async Task b()
    {

            throw new NullReferenceException("未将你妈绑定到实例");
             await ........
    }

It doesn't work.The exception doesn't write.

It is too Weird!.What I want is just that there is one place to handle all of those exceptions together .But I failed.Is somebody know how to deal with this Situation?Please help me,I feel like I'm losing my mind!


Solution

  • Your problem is due to StartNew not being async-aware. This is one of the reasons to avoid StartNew that I describe on my blog.

    In short, the reason you're not seeing the exceptions is because passing an async lambda to StartNew will return a Task<Task> instead of a plain Task, and you need to Unwrap the nested task in order to get the result of the async method.

    You can unwrap the task like this:

    childTasks[1] = tf.StartNew(async () =>
    {
      throw new Exception("dddddd");
    }).Unwrap();