async properties could be added to the language without much difficulty (well, property getters could, at least). Properties are just syntactic sugar for getter and setter methods, and it wouldn’t be a huge leap to make these methods
async properties are not allowed.
This is a purposeful design decision, because “asynchronous properties” is an oxymoron. Property getters should return current values; they should not be kicking off background operations. Also, the semantics behind an “asynchronous setter” are not at all clear.
Usually, when someone wants an “asynchronous property”, what they really want is one of these:
- An asynchronous operation that returns a value.
- A value that is expensive to create, but should be cached for future use.
- A value that can be used in data-binding but which must be calculated or retrieved asynchronously.
We’ll look at each of these in turn.
If your “property” needs to be asynchronously evaluated every time it’s accessed, then you’re really talking about an asynchronous operation.The best solution is to change the property to an
async method. Semantically, it shouldn’t be a property.
It is possible to have a property return a
Task<T> just by returning the result of an
However, I do not recommend this approach. If every access to a property is going to kick off a new asynchronous operation, then that “property” should really be a method:
Personally, I think the asynchronous method makes it clearer that a new asynchronous operation is initiated every time.
In this case, you only want the asynchronous operation executed once: the first time it’s requested. After the operation completes, the result of the operation should be cached and returned immediately.
The easiest solution for this is to use
AsyncLazy<T>, available in the AsyncEx library:
In this case, I find the property syntax acceptable, since there’s only one actual asynchronous operation and every method waiting on it will wait on the same operation.
Data binding requires immediate (synchronous) results, and it can only deal with a limited set of types. Data binding will not give awaitable types any special treatment, so the type of an “asynchronous property” used for data binding must be the type of the result of the asynchronous operation (e.g.,
int instead of
For this to work, the data-bound value must be initially set to some default or “unknown” value, and the type can implement
INotifyPropertyChanged to let the data binding know when the asynchronous value has been determined.
In the example code above, I’m assuming that the code constructing a
MyClass will call its
InitializeAsync method. Alternatively, if this instance is contained in an enclosing data bound instance, you could wrap the construction and
InitializeAsync into an asynchronous factory method as we discussed last time.
If your property value is simply the result of a
Task<TResult>, then you can use the NotifyTaskCompletion type in the AsyncEx library to make this even easier:
In this case, you can databind to
MyProperty.Result, which will be initialized to the default value (
null). When the
GetValueAsync task completes,
MyProperty.Result will be updated to the result value (
INotifyPropertyChanged, so this change will be picked up automatically by the data binding.
Update (2014-12-01): For more details, see Recipe 10.4 in my Concurrency Cookbook.