I've been reading about task-like and awaitable types. I think I've got a good grasp on the basic mechanics of it (awaiter, asyncmethodbuilder...) but there's something amiss when I try to understand the usage of ConfigureAwait(false) in such scenario (if that is even possible).
My questions are:
Is ConfigureAwait reserved for "true" Tasks, meaning the usage or not of the SynchronizationContext?
If so, and say you're coding a general purpose library that exposes it's own implementations of task-like types, should you just use ConfigureAwait(false) when your code encounters Tasks?
Thanks.
If the task-like types of your library does not capture the context when awaited, then the users of your library will not be able to do this:
private async void Button_Click(object sender, EventArgs e)
{
string input = Textbox1.Text;
TaskLike<string> taskLike = YourLibrary.ProcessAsync(input);
string result = await taskLike;
Label1.Text = result // InvalidOperationException: Cross-thread operation not valid
}
On the other hand if the task-like types of your library always capture the synchronization context when awaited, then your library will be inefficient as a building block of other libraries, and will require from the other libraries authors to jump through hoops in order to invoke your library in a synchronization-context-free manner. So making your task-like types configurable regarding capturing the synchronization context should be a desirable feature.
Regarding whether you should use ConfigureAwait(false)
when the internal code of your library encounters standard Task
s, it depends on whether your library accepts caller-supplied lambdas. If for example your library includes a method like this:
public TaskLike<string> ProcessAsync(Action action);
...then invoking the action
after awaiting internally something with ConfigureAwait(false)
may result to cross-thread violation exceptions, if the caller's lambda includes thread-affine code like reading properties of UI controls. To solve this problem may require to introduce a configuration parameter continueOnCapturedContext
in the method's signature. At least this is the solution chosen by the Polly library.