如何从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属性”时,他们真正想要的是其中之一:

  1. 一个返回值的asynchronous方法。 在这种情况下,将属性更改为async方法。
  2. 可以在数据绑定中使用的值,但必须asynchronous计算/检索。 在这种情况下,可以使用包含对象的async工厂方法,也可以使用async InitAsync()方法。 数据绑定值将是default(T)直到计算/检索值为止。
  3. 一个创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(); } }