【问题标题】:Code Contracts and Tasks代码契约和任务
【发布时间】:2014-11-24 14:53:51
【问题描述】:

代码契约只是像对待任何其他变量一样对待任务,而不是异步等待结果。因此,以下场景将不起作用,并导致 Contracts 异常,因为在方法返回时,它是一个不完整的任务,并且不会在那个时间点设置结果。以下情况是否有任何合理的解决方法?

public Task LoadAppModel()
{
    Contract.Ensures(app.User != null);
    Contract.Ensures(app.Security != null);
    Contract.Ensures(app.LocalSettings != null);

    return Task.WhenAll(
        store.GetUserAsync().ContinueWith(t => { app.User = t.Result; }),
        store.GetSecurityAsync().ContinueWith(t => { app.Security = t.Result; }),
        store.GetLocalSettingsAsync().ContinueWith(t => { app.LocalSettings = t.Result; }));
}

任何建议将不胜感激。 :) 我宁愿不打破合同模式。

【问题讨论】:

  • Task.WaitAll()代替WhenAll()怎么样?
  • 这打破了异步性。唯一不破坏异步的方法似乎是将其拆分为多个方法。
  • 但是你描述它的方式,它不是异步的吗? C#Task 类在 async/await 功能之前就已经存在,并且并不总是表明使用它们的方法是 Async...
  • 它将是异步的。等待发生在 sn-p 之外。
  • 接受答案后情况发生了变化。添加此评论,因为 google 将此线程作为有关 CodeContract 和异步的第一个来源之一。看看我的回答:stackoverflow.com/questions/9164213/…

标签: c# .net async-await task code-contracts


【解决方案1】:

代码合同和async 不能很好地结合在一起,所以你不能真正使用Contract.Ensures

但是有一个解决方法。您可以将您的方法从 Task-returning 方法更改为 async 一种(无论如何这会更干净)并改用 Contract.Assume

public async Task LoadAppModel()
{
    var userTask = store.GetUserAsync();
    var securityTask = store.GetSecurityAsync();
    var settingsTask = store.GetLocalSettingsAsync();
    await Task.WhenAll(userTask, securityTask,settingsTask);

    app.User = userTask.Result;
    app.Security = securityTask.Result;
    app.LocalSettings = settingsTask.Result;

    Contract.Assume(app.User != null);
    Contract.Assume(app.Security != null);
    Contract.Assume(app.LocalSettings != null);
}

【讨论】:

  • 这是一个巧妙的技巧。然而,假设改变了上下文,使得许多代码契约的派生特性(例如文档)变得无用。但我想这是在代码合约支持异步之前最好的解决方案。将其标记为答案,直到实现异步。谢谢:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-20
  • 1970-01-01
相关资源
最近更新 更多