Unity3dAsyncAwaitUtil icon indicating copy to clipboard operation
Unity3dAsyncAwaitUtil copied to clipboard

Should TaskExtensions.AsIEnumerator unwrap AggregateException?

Open dubois opened this issue 5 years ago • 0 comments

I'm trying to incrementally convert our codebase from coroutines to async/await. Doing it incrementally means a lot of "await " and "Task.AsIEnumerator()" to convert between the two styles at the boundaries.

One issue I've found is that converting a Coroutine -> async Task is not as simple as changing the method from "IEnumerator DoSomethingCoroutine()" -> "async Task DoSomethingAsync()" and fixing up callers to append ".AsIEnumerator()", because exceptions that propagate from Task and AsIEnumerator() are wrapped with AggregateException().

I'm assuming that the main use case of Task.AsIEnumerator is to help with the transition process, so I think there's a good argument for unwrapping the AggregateException. On the other hand, I'm not sure when the AggregateException might contain 2 or more exceptions and what AsIEnumerator should do in that case.

Here's some sample code that illustrates the issue:

    class MyCustomException : Exception {}

    IEnumerator<object> CallerCoroutine() {
        // Old code is sometimes verbose, for call stacks and exception propagation
        using (var cr = DoSomethingCoroutine()) {
            while (true) {
                try {
                    if (!cr.MoveNext()) { break; }
                } catch (MyCustomException e) {
                    // ...
                }
                yield return cr.Current;
            }
        }

        // Simple automated refactor doesn't work because the exception is now AggregateException
        using (var cr = DoSomethingAsync().AsIEnumerator()) {
            // ... body is same as above ...
        }
    }

    IEnumerator<object> DoSomethingCoroutine() {
        if (UnityEngine.Random.value > .5f) { throw new MyCustomException(); }
        yield return null;
    }

    async Task<object> DoSomethingAsync() {
        if (UnityEngine.Random.value > .5f) { throw new MyCustomException(); }
        await Awaiters.NextFrame;
        return null;
    }

dubois avatar Dec 03 '19 23:12 dubois