How to tell if Task has been "observed"?

时间:2015-10-30 23:52:35

标签: c# .net exception async-await task-parallel-library

This is a follow-up to this question. I've also read Stephen Toub's "Tasks and Unhandled Exceptions" and I think I understand how tasks and exceptions work and what "observed task" means. I however cannot figure out how to tell if a Task has been observed or not. Is that possible at all without using reflection? I'd like to borrow @Noseratio's code as an example: static async void Observe(Task task) { await task; } // ... var taskObserved = false; var task = DoSomething() try { bool ready = await DoSomethingElse(); if (!ready) return null; var value = await DoThirdThing(); // depends on DoSomethingElse taskObserved = true; return value + await task; } finally { if (!taskObserved) Observe(task); } If we could tell whether the task had been observed, this could be made simpler and more readable: static async void Observe(Task task) { if (!task.WasObserved) await task; } // ... var task = DoSomething() try { bool ready = await DoSomethingElse(); if (!ready) return null; var value = await DoThirdThing(); // depends on DoSomethingElse return value + await task; } finally { Observe(task); }

1 个答案:

答案 0 :(得分:5)

Tasks have no idea whether they've been awaited or not. It's kind of like asking if an integer knows if it's been added to another integer or not. However, the task's exception can be observed, and whether the exception has been observed is in fact remembered by the task. It's important to distinguish between unobserved exceptions and unawaited tasks. The runtime has some special logic for unobserved task exceptions, but does not do anything special for unawaited tasks. You really should not write code that depends on whether a task has been awaited. If the semantics for DoSomething are that it always should be awaited even if the result is ignored (a very odd - but technically valid - requirement), then this code should suffice: var task = DoSomething(); try { bool ready = await DoSomethingElse(); if (!ready) return null; var value = await DoThirdThing(); // depends on DoSomethingElse return value + await task; } finally { await task; } On the other hand, if the semantics of DoSomething are that the task can be ignored if the result isn't needed after all (which is far more likely the case), then this code should suffice: var task = DoSomething(); bool ready = await DoSomethingElse(); if (!ready) return null; var value = await DoThirdThing(); // depends on DoSomethingElse return value + await task; No need to mess around with worrying about whether a task has been awaited.