代码合约 - 不错,处于边缘,但还没有准备好迎接黄金时段?
我对 .NET 4 中引入的代码契约着迷(尽管是在 DevLabs 的帮助下)。但一张精美的印刷品让我冷静下来。它是这么说的:
- 目前,除了不使用后置条件之外,在线程安全方法中在锁之外调用后置条件时,没有解决该问题的方法。
- .NET 依赖于二进制重写器,因此使构建速度变慢。
- 使用代码契约也可能会导致运行时性能下降。
- 不能用于安全敏感检查,因为可以在运行时通过处理 ContractFailed 事件来规避它们。
对我来说最大的是第一个。我不知道是否有人再编写单线程应用程序。因此,如果代码契约不能支持多线程,我认为它们没有多大用处。或者也许我不应该对此过分强调,因为后置条件用于断言方法本身的内部结构,可以进行单元测试。
顺便说一句,我没有找到任何东西,也没有尝试反汇编我的代码来查看先决条件被注入的位置。我想在一个简单的方法中,当 lock() 首先执行时,在它之后注入检查很简单,但在一个相当复杂的方法中,当锁定发生在中间的某个地方时,这可能是一个问题。或者如果使用了除lock()之外的其他机制。
I got really captivated by code contracts introduced in .NET 4 (though with the help of DevLabs). But one fine print cooled me off quite a bit. Here is what it says:
- There is currently no workaround the problem when postconditions are called outside of lock in a thread-safe method except for not using them.
- .NET relies on a binary rewriter thus making the build slower.
- Using code contracts may also incur a runtime performance hit.
- Can't be used for security-sensitive checks because they can be circumvented at runtime by handling the ContractFailed event.
The biggest for me is the first one. I don't know if anyone write single-threaded apps anymore. So if code contracts are not able to support multi-threading, I don't see much use of them. Or maybe I shouldn't be stressed too much about that because postconditions are for asserting the internals of the method itself, which can be unit-tested.
BTW, I haven't found anything and I didn't try to disassemble my code to see where preconditions are injected. I suppose in a simple method when lock() goes first, it's simple to inject checks right after it but in a rather complicated method, when locking occurs somewhere in the middle, it may be an issue. Or if some other mechanisms other than lock() are used.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您似乎将“编写多线程应用程序”与“使每个类都线程安全”混淆了。撇开 定义术语“线程安全”的棘手问题我建议您的类中很少应该在大多数应用程序中使用锁定。
一般来说,我编写了很多类,这些类没有尝试显式地线程安全,但同样没有任何线程依赖性。他们假设,如果您要从多个线程使用它们,则一次只能从一个线程执行此操作,并使用适当的内存屏障来确保一个线程中所做的更改在下一个使用它们的任何线程中都可见。
然后,执行必要协调的类相对较少。
现在,代码契约的问题可能会使这几个类变得足够弱,从而使整个想法崩溃......但我不认为一开始就这样。
我对代码合约将面临的问题有些警惕,因为 C# 编译器会做越来越多的工作来重写你的代码...我不知道合约团队是否已经解决了迭代器块的问题,但即使他们已经解决了当 C# 5 推出异步方法时,我必须再次这样做......
You seem to be confusing "writing multi-threaded apps" with "making every class thread-safe". Leaving aside the tricky question of defining the term "thread safety" I would suggest that very few of your classes should use locking in most apps.
Generally I write lots of classes which make no attempt to be explicitly thread-safe, but equally don't have any thread dependencies. They assume that if you're going to use them from multiple threads, you'll only do so from one thread at a time, with appropriate memory barriers to make sure changes made in one thread are visible in whatever thread next uses them.
There are then relatively few classes which perform the necessary coordination.
Now, it's possible that the problems with Code Contracts will make those few classes sufficiently weak as to make the whole think come tumbling down... but I wouldn't assume that to start with.
I'm somewhat warier of the issues Code Contracts will face with the C# compiler doing more and more work rewriting your code... I don't know whether the Contracts team has addressed issues of iterator blocks yet, but even if they have they'll have to do so again when C# 5 comes out with async methods...
这并不是真正的问题 - 如果您在线程安全方法的锁定语句之外进行检查,您也可能会遇到问题。针对这个小小的“限制”调整您的实现。问题是代码重写器如何知道您必须锁定资源?我认为这种限制将持续很长一段时间。
是的,必须评估、生成和保存一些 IL,以注入一些 IL 构建新的依赖项 = 当然需要更多时间。
这也不是不寻常或问题,更多的代码(为代码合约生成)=更慢。基本上你只是有更多的代码以及你可能通过代理类运行的代码,所以有更多的代码+可能的代理。
是的,不要这样做。您甚至不必拆卸/重新组装程序集即可跳过潜在的安全检查。如果可能的话,将所有与安全相关的控制流保留在服务器上(无论是 Web 还是数据库),或者在本地尝试尽可能地混淆代码。
Not really a problem—if you do a check yourself outside of a lock statement in thread-safe method you can run into a problem as well. Adjust your implemenation for this little 'limitation'. The question is how code rewriter going to know that you must be locking a resource? I think this limitation will stay on for a long time.
Yes, some IL has to be evaluated, generated, and saved to inject some IL build new dependencies = more time of course.
Also not unusual or a problem, more code (generated for the code contracts) = slower. You just have more code basically and what you may be running through a proxy class as well so there is more code + possible proxy.
Yes don't do that. You don't even have to disaasble/reassemble the assembly to skip a potential security check. Keep any security related control flows on the server (be it web or db) if possible, or try to obfuscate your code to your best ability if local.