When Microsoft announced the Task Parallel Library, C# programmers everywhere rejoiced. Simplified threads? Error handling within the library itself? What could possibly go wrong?
Just about everything, as it turns out.
A task requires a root in order to be properly awaited. For instance:
// An awaitable task
public Task YouCanAwaitMe() { }
// A root where you an await a task
public async Task IWillAwait()
{
await YouCanAwaitMe().WithoutChangingContext();
}
Unfortunately, a Xamarin app doesn't have any valid roots. For instance, not at:
- Constructors
- Content changed
- Binding context changed
- Event handlers
- Global messages
- Overrides
- Property Setters
Any location that fails to provide a Task signature is a false root. This causes unsafe results:
public class FalselyRootedView : ContentView
{
protected override async void OnBindingContextChanged()
{
base.OnBindingContextChanged();
// Mega hack -- called from a void method (illegal!)
await StartUpViewModel().WithoutChangingContext();
}
public virtual Task StartUpViewModel()
{
return Task.CompletedTask;
}
}
// Derive and consume the falsely rooted view as if it were valid
public class FalseConsumer : FalselyRootedView
{
pubic override async Task StartUpViewModel()
{
// Everything seems OK from this perspective, but this task can proceed at any time and
// without our control; it was never properly awaited. Anything relying on it will
// accelerate into a race condition; variables will not be set on time; nothing can
// be relied upon in a predictable order.
await SomeOtherTask().WithoutChangingContext();
}
}
Until Microsoft converts all current code signatures to Tasks, programmers are stuck using these sorts of risky mechanisms.
See the unit tests.
Each page describes a problem and its Responsive solution: