如何从getter或setter调用asynchronous方法?
什么是从C#中的getter或setter调用asynchronous方法最优雅的方式?
这里有一些伪代码来帮助解释我自己。
async Task<IEnumerable> MyAsyncMethod() { return await DoSomethingAsync(); } public IEnumerable MyList { get { //call MyAsyncMethod() here } }
没有技术上的原因, async
属性不允许在C#中。 这是一个有目的的devise决定,因为“asynchronous属性”是一个矛盾。
属性应该返回当前值; 他们不应该开始后台操作。
通常,当有人想要一个“asynchronous属性”时,他们真正想要的是其中之一:
- 一个返回值的asynchronous方法。 在这种情况下,将属性更改为
async
方法。 - 可以在数据绑定中使用的值,但必须asynchronous计算/检索。 在这种情况下,可以使用包含对象的
async
工厂方法,也可以使用async InitAsync()
方法。 数据绑定值将是default(T)
直到计算/检索值为止。 - 一个创build成本很高的值,但应该被caching以供将来使用。 在这种情况下, 从我的博客或AsyncEx库使用
AsyncLazy
。 这会给你一个await
财产。
更新:我介绍了我最近的一个“asynchronousOOP”博客文章中的asynchronous属性 。
您不能asynchronous调用它,因为没有asynchronous属性支持,只有asynchronous方法。 因此,有两种select,都利用了CTP中的asynchronous方法实际上只是一个返回Task<T>
或Task
:
// Make the property return a Task<T> public Task<IEnumerable> MyList { get { // Just call the method return MyAsyncMethod(); } }
要么:
// Make the property blocking public IEnumerable MyList { get { // Block via .Result return MyAsyncMethod().Result; } }
由于我的解耦架构,我真的需要调用来自get方法。 所以我想出了以下的实现。
用法: 标题位于ViewModel中,或者静态声明为页面资源的对象。 绑定到它,当getTitle()返回时,该值将被填充而不会阻塞UI。
string _Title; public string Title { get { if (_Title == null) { Deployment.Current.Dispatcher.InvokeAsync(async () => { Title = await getTitle(); }); } return _Title; } set { if (value != _Title) { _Title = value; RaisePropertyChanged("Title"); } } }
我认为我们可以等待刚刚返回null的值,然后得到真正的值,所以对于Pure MVVM(例如PCL项目),我认为以下是最优雅的解决scheme:
private IEnumerable myList; public IEnumerable MyList { get { if(myList == null) InitializeMyList(); return myList; } set { myList = value; NotifyPropertyChanged(); } } private async void InitializeMyList() { MyList = await AzureService.GetMyList(); }
我以为.GetAwaiter()。GetResult()正是这个问题的解决scheme,没有? 例如:
string _Title; public string Title { get { if (_Title == null) { _Title = getTitle().GetAwaiter().GetResult(); } return _Title; } set { if (value != _Title) { _Title = value; RaisePropertyChanged("Title"); } } }
由于您的“asynchronous属性”是在视图模型中,您可以使用AsyncMVVM :
class MyViewModel : AsyncBindableBase { public string Title { get { return Property.Get(GetTitleAsync); } } private async Task<string> GetTitleAsync() { //... } }
它将负责为您同步上下文和属性更改通知。
有一件事要注意:在IEnumerable结果返回的情况下,yield return具有更好的性能,并且不需要转换为IEnumerable。
public IEnumerable MyList { get { yield return MyAsyncMethod(); } }