代码契约和异步
将后置条件添加到返回 Task
的异步方法的推荐方法是什么?
我已阅读以下建议:
http://social.msdn.microsoft.com/Forums/hu-HU/async/thread/52fc521c-473e-4bb2-a666-6c97a4dd3a39
该文章建议将每个方法实现为同步,收缩它,然后将异步对应物实现为简单的包装器。不幸的是,我不认为这是一个可行的解决方案(也许是由于我自己的误解):
- 异步方法虽然被假定为同步方法的包装器,但没有任何真正的代码契约,因此可以按照它的意愿行事。
- 致力于异步的代码库不太可能为所有内容实现同步对应物。因此,在其他异步方法上实现包含 wait 的新方法将被迫异步。这些方法本质上是异步的,不能轻易转换为同步。它们不仅仅是包装纸。
即使我们通过说我们可以使用 .Result
或 .Wait()
而不是 await
(这实际上会导致一些< code>SyncContexts 会导致死锁,并且无论如何都必须在异步方法中重写),我仍然相信第一点。
是否有任何替代想法,或者我是否遗漏了有关代码契约和 TPL 的任何内容?
What is the recommended way for adding postconditions to async methods which return Task<T>
?
I have read the following suggestion:
http://social.msdn.microsoft.com/Forums/hu-HU/async/thread/52fc521c-473e-4bb2-a666-6c97a4dd3a39
The post suggests implementing each method as synchronous, contracting it, and then implementing an async counterpart as a simple wrapper. Unfortunately I don't see this as a workable solution (perhaps through my own misunderstanding):
- The async method, although assumed to be a wrapper for the sync method, is left without any real code contract and can therefore do as it wishes.
- Codebases which are committed to asynchrony are unlikely to implement sync counterparts for everything. As a result, implementing new methods which contain
await
s on other async methods are consequently forced to be async. These methods are intrinsically asynchronous and cannot easily be converted to synchronous. They are not simply wrappers.
Even if we invalidated the latter point by saying we could use .Result
or .Wait()
instead of await
(which would actually cause some SyncContext
s to deadlock, and would have to be re-written in the async method anyway), I'm still convinced about the first point.
Are there any alternative ideas, or is there anything that I've missed about code-contracts and TPL?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我已经向异步团队指出了这一点,正如其他人所做的那样。目前,合约和异步(几乎)是相互排斥的。所以,至少微软的一些人意识到了这个问题,但我不知道他们打算采取什么措施。
我不建议将异步方法编写为同步方法的包装器。事实上,我倾向于做相反的事情。
前提条件可以发挥作用。我最近没有尝试过;您可能需要一个包含先决条件的异步方法的小包装器。
后置条件几乎被破坏了。
断言和假设确实可以正常工作,但静态检查器确实受到限制,因为后置条件被破坏。
不变量在异步世界中没有多大意义,因为可变状态往往会造成阻碍。 (异步轻轻地将您从 OOP 推向函数式风格)。
希望在 VS vNext 中,合约将使用异步感知的后置条件进行更新,这也将使静态检查器能够更好地处理异步方法中的断言。
同时,您可以通过编写假设来拥有假装后置条件:
代码契约的某些用法是不可能的 - 例如,在接口或基类的异步成员上指定后置条件。
就我个人而言,我刚刚在异步代码中完全避免了合约,希望微软能在几个月内修复它。
I've pointed this out to the Async team, as others have done. Currently, Contracts and Async are (almost) mutually exclusive. So, at least some people in Microsoft are aware of the problem, but I'm not aware of what they're planning to do about it.
I do not recommend writing async methods as wrappers for sync methods. In fact, I would tend to do the opposite.
Preconditions can work. I haven't tried it recently; you may need a small wrapper around your async method that includes the preconditions.
Postconditions are pretty much broken.
Assertions and assumptions do work normally, but the static checker is really limited because postconditions are broken.
Invariants don't make as much sense in the Async world, where mutable state tends to just get in the way. (Async gently pushes you away from OOP and towards a functional style).
Hopefully in VS vNext, Contracts will be updated with an async-aware sort of postcondition, which would also enable the static checker to work better with assertions in async methods.
In the meantime, you can have a pretend-postcondition by writing an assume:
Some usages of code contracts just aren't possible - e.g., specifying postconditions on async members of interfaces or base classes.
Personally, I've just avoided Contracts entirely in my Async code, hoping that Microsoft will fix it in a few months.
输入此内容,但忘记点击“发布”...:)
目前尚无对此的专门支持。你能做的最好的事情就是这样(不使用
async
关键字,但同样的想法 - 重写器可能会在异步CTP下以不同的方式工作,我还没有尝试过):但是,这意味着“async”方法在任务完成评估之前不会真正返回,因此只有 3 秒过去后才会打印“processing”。这类似于延迟返回 IEnumerable 的方法的问题 - 合约必须枚举 IEnumerable 中的所有项目以确保条件成立,即使调用者获胜实际上并没有使用所有的物品。
您可以通过将契约模式更改为先决条件来解决此问题,但这意味着实际上不会检查后置条件。
静态检查器也无法将
Result
与 lambda 连接起来,因此您会收到“Ensures unproven”消息。 (一般来说,静态检查器无论如何都不会证明有关 lambdas/委托的事情。)我认为为了获得对 Tasks/await 的适当支持,代码契约团队必须对特殊情况的任务进行特殊处理,以便仅在访问
结果
字段。Typed this up but forgot to hit "Post"... :)
There's not specialised support for this at the moment. The best you can do is something like this (not using
async
keyword, but the same idea - it's possible the rewriter will work differently under the async CTP, I haven't tried it yet):However, this means that the 'async' method won't actually return until the Task has finished evaluating, so "processing" won't be printed until 3 seconds have elapsed. This is similar to the problem with methods that lazily return
IEnumerable
s — the Contract has to enumerate all items in theIEnumerable
to ensure that the condition holds, even if the caller won't actually use all the items.You can work around this by changing your contracts mode to
Preconditions
, but this means that no post-conditions will actually be checked.The static checker also can't connect the
Result
with the lambda, so you'll get an "Ensures unproven" message. (In general the static checker doesn't prove things about lambdas/delegates anyway.)I think to get proper support for Tasks/await, the Code Contracts team will have to special-case Tasks to add the precondition check only upon access of the
Result
field.将新答案发布到这个旧线程,因为它是由谷歌返回的,作为有关 CodeContract 和 Async 当前合同的问题的第一个答案,
返回 Task 的异步方法工作正常,无需避免它们。
异步方法的标准合约:
如果您认为该合约看起来不正确,我确实同意它至少看起来具有误导性,但它确实有效。而且合同重写者似乎并没有强制过早评估任务。
当斯蒂芬提出一些疑问时,我进行了更多测试,合同在我的案例中正确地完成了任务。
用于测试的代码:
Posting new answer to this old thread as it is returned by google as the first answer to question about CodeContract and Async
Curently Contract on async methods returning Task are working correctly, and there is no need to avoid them.
Standart contract for async method:
If you think that contract does not look correct i do agree it looks misleading at the least, but it does work. And it does not look like that contract rewriter forces evaluation of task prematurely.
As Stephen raised some doubts made some more testing and contracts in my case did their thing correctly.
Code used for testing: