UniTask icon indicating copy to clipboard operation
UniTask copied to clipboard

A confusion

Open Summid opened this issue 3 years ago • 2 comments

Can someone help me with a question? The delegate field continuationAction in ResourceRequestAwaiter struct, why is it always null when complete either in async or sync in function GetResult() ? I have read the source code several times, and did not find when it was set to null. Did i miss something?

public struct ResourceRequestAwaiter : ICriticalNotifyCompletion
        {
            ResourceRequest asyncOperation;
            Action<AsyncOperation> continuationAction;
            public ResourceRequestAwaiter(ResourceRequest asyncOperation)
            {
                this.asyncOperation = asyncOperation;
                this.continuationAction = null;
            }

            public bool IsCompleted => asyncOperation.isDone;

            public UnityEngine.Object GetResult()
            {
                //why is continuationAction here always null when complete either in async or sync?
                if (continuationAction != null)
                {
                    asyncOperation.completed -= continuationAction;
                    continuationAction = null;
                    var result = asyncOperation.asset;
                    asyncOperation = null;
                    return result;
                }
                else
                {
                    var result = asyncOperation.asset;
                    asyncOperation = null;
                    return result;
                }
            }

            public void OnCompleted(Action continuation)
            {
                UnsafeOnCompleted(continuation);
            }

            public void UnsafeOnCompleted(Action continuation)
            {
                Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
                continuationAction = PooledDelegate<AsyncOperation>.Create(continuation);
                asyncOperation.completed += continuationAction;
            }
        }

Summid avatar Jul 28 '22 15:07 Summid

When the code executes to GetResult(), the variables of ResourceRequestAwaiter become the default values set in the constructor, so the value of continuationAction is null. But when I changed the type of ResourceRequestAwaiter from struct to class, the above problem disappeared. I know the generated state machine is using a reference to awaiter, so the problem is rather strange, although the code works fine.

Summid avatar Aug 02 '22 09:08 Summid

Hi!

I wrote the code similar to the generated state machine to observe its behavior. When the state machine invoke builder.AwaitUnsafeOnCompleted, it will modify the value of Awaiter's fields in Awaiter.UnsafeOnCompleted(Action continuation). But after this, the ''captured" member fields in continuation (MoveNext also) still keep the initial value (I guess there is a awaiter copy during call Awaiter.UnsafeOnCompleted). So, when the state machine completes successfully, and Awaiter.GetResult() will be called, continuationAction is of course empty.

Looks like my confusion is resolved. By the way, thanks for making such a cool UniTask library, I learned a lot from your code, you are my hero 😸 .

Summid avatar Aug 03 '22 03:08 Summid

This issue is stale because it has been open 90 days with no activity. Remove stale label or comment or this will be closed in 7 days.

github-actions[bot] avatar Nov 02 '22 00:11 github-actions[bot]