严格的MVVM和Task.ConfigureAwait(false)

时间:2014-10-07 12:28:32

标签: c# wpf mvvm async-await

我正在重写MVVM框架的某些部分以使用async / await功能,请考虑以下VM代码:

private async Task LoadDossier(int ID)
    {
        //VM INotifyProperty
        Dossiers = new ObservableCollection<Dossier>(await BubManager.GetAllBubDossiersForEmployeeByDossierIdAsync(ID).ConfigureAwait(false));
        //VM INotifyProperty
        SelectedDossier = Dossiers.First(x => x.Id == ID);
        //VM INotifyProperty
        DossierEmployer = await EmployerManager.GetEmployerByIdAsync(SelectedDossier.EmployerId).ConfigureAwait(false);
        //VM INotifyProperty
        DossierEmployee = await EmployeeManager.GetEmployeeByIdAsync(SelectedDossier.EmployeeId).ConfigureAwait(false);
        //All VM INotifyProperties
        if (SelectedDossier != null && DossierEmployer != null)
        {
            RszNr = DossierEmployer.RszNr;
            FundsNr = DossierEmployer.FundsNr;
            RrNr = DossierEmployee.RrNr;
        }
        RefreshGlobalCommanding();
    }

由于我使用的是严格的MVVM,因此这里没有一个需要UI线程的属性,因此我在任何地方都使用ConfigureAwait(false)。我知道在ObservableCollection添加/删除时无法做到这一点,但这不是这种情况。

  • 这段代码是一个好习惯吗?
  • 如果是,那为什么不能将此作为默认行为?不断输入ConfigureAwait(false)不一定有助于提高可读性IMO

修改

在与斯蒂芬讨论后,我得出结论,它基本上是一样的。

  • 如果你使用ConfigureAwait(false),你告诉WPF回调不必在UI线程上。设置INotifyProperty时,WPF会确保UI线程获得通知。
  • 如果你没有WPF确保回调在UI线程上,那就没有问题。

两种情况都使WPF在某些时候进行UI线程编组。但是,我比较了两者的表现并且存在显着差异。我执行了一个循环1000次,其中一个对象绑定到一个视图,然后再次设置为null,这是以毫秒为单位的结果:

一个等待呼叫,任务延迟为10毫秒

  • 15623ms ConfigureAwait(false)
  • 51700ms没有

三个等待任务延迟为10毫秒的呼叫

  • 46917ms ConfigureAwait(false)
  • 82647ms没有

这个基准测试远非完美,但是似乎编组返回UI线程的属性比在同一个线程上运行await调用之后强制执行所有内容要便宜。这需要更多的测试来为所有场景提供明确的答案。

我只是把它放在这里,以证明两者之间存在差异。我的建议是在这种情况下不使用ConfigureAwait,因为它在更改代码时会增加异常的可能性,可读性较差,同事可能无法理解这一点,并且通过使用它来获得错误的安全感。

1 个答案:

答案 0 :(得分:3)

  

这段代码是一个好习惯吗?

就个人而言,我选择将所有数据绑定属性视为具有UI亲和力。

一个原因是不同的MVVM框架在这方面具有不同的能力; WPF会为你处理这个问题(对于简单的属性),但其他人不会这样做。

  

如果是,那为什么不能将此作为默认行为?

async出现在CTP中时,有关await的默认行为的讨论很多。各方都有利弊。