How to 'await' a listener properly? Replacing a hacky spin-lock solution

283 Views Asked by At

I am working on a xamarin project with a partner. Xamarin allows the use of C# in coding for iOS or Android. Here is an example of some code a coworker wrote that I feel could be done in a substantially better way:

alert = new AlertDialog.Builder (Act);
alert.SetOnDismissListener(new OnDismissListener(() => {
    blocked = false;
}));

alert.SetNegativeButton (noOption, (senderAlert, args) => {
    affirmative = false;
    alert.Dispose();
} );

alert.SetPositiveButton (yesOption, (senderAlert, args) => {
    affirmative = true;
    alert.Dispose();
} );
    //display the alert
    //call GetAffirmative()
...
...
...
private async Task<bool> GetAffirmative()
{
    int secondsToDelay = 1;
    await Task.Delay(TimeSpan.FromSeconds(secondsToDelay));
    if (!blocked) {
        return affirmative;
    }
    return await GetAffirmative ();
}

Essentially it creates an alert that acts on two booleans: the affirmative boolean is set on a yes/no response, and the blocked boolean is used in a spin-lock. When the spin-lock resolves due to the 'blocked' boolean being set to false, it returns from the await.

I really don't like this solution. What is a better option? (Preferably a new paradigm, rather than simply changing from recursion to a loop, etc)

1

There are 1 best solutions below

0
On BEST ANSWER

Use TaskCompletionSource. That's how you create an asynchronous task and complete it when you want.

Create it when a call is made to GetAffirmative, await its Task property and complete it instead of setting a false to blocked:

alert.SetOnDismissListener(new OnDismissListener(() => {
    _tcs.SetResult(false);
}));

...

TaskCompletionSource<bool> _tcs;
private async Task<bool> GetAffirmative()
{
    _tcs = new TaskCompletionSource<bool>();
    await _tcs.Task;
    return affirmative;
}

There isn't a non-generic TaskCompletionSource so I'm using a bool one, any other type would work just as well.