在对象不变量的代码中我可以有多自由?
我试图演示代码契约中的不变量,并且我想我应该给出一个排序的字符串列表的示例。 它在内部维护一个数组,并具有用于添加等的备用空间 - 基本上就像 List
一样。 当它需要添加一个项目时,它将其插入到数组中,等等。我认为我有三个不变量:
- 计数必须合理:非负且最多与缓冲区大小一样大
- 缓冲区的未使用部分中的所有内容应该为 null
- 缓冲区已使用部分中的每个项目至少应与之前的项目一样“大”
现在,我尝试以这种方式实现:
[ContractInvariantMethod]
private void ObjectInvariant()
{
Contract.Invariant(count >= 0 && count <= buffer.Length);
for (int i = count; i < buffer.Length; i++)
{
Contract.Invariant(buffer[i] == null);
}
for (int i = 1; i < count; i++)
{
Contract.Invariant(string.Compare(buffer[i], buffer[i - 1]) >= 0);
}
}
不幸的是, ccrewrite 很混乱向上循环。
用户文档说该方法应该只是对Contract.Invariant的一系列调用。 我真的必须将代码重写为这样吗?
Contract.Invariant(count >= 0 && count <= buffer.Length);
Contract.Invariant(Contract.ForAll
(count, buffer.Length, i => buffer[i] == null));
Contract.Invariant(Contract.ForAll
(1, count, i => string.Compare(buffer[i], buffer[i - 1]) >= 0));
这有点难看,尽管它确实有效。 (请注意,这比我之前的尝试要好得多。)
我的期望是否不合理? 我的不变量不合理吗?
(也作为问题提出代码契约论坛。我将自己在此处添加任何相关答案。)
I'm trying to demonstrate invariants in Code Contracts, and I thought I'd give an example of a sorted list of strings. It maintains an array internally, with spare space for additions etc - just like List<T>
, basically. When it needs to add an item, it inserts it into the array, etc. I figured I had three invariants:
- The count must be sensible: non-negative and at most as big as the buffer size
- Everything in the unused part of the buffer should be null
- Each item in the used part of the buffer should be at least as "big" as the item before it
Now, I've tried to implement that in this way:
[ContractInvariantMethod]
private void ObjectInvariant()
{
Contract.Invariant(count >= 0 && count <= buffer.Length);
for (int i = count; i < buffer.Length; i++)
{
Contract.Invariant(buffer[i] == null);
}
for (int i = 1; i < count; i++)
{
Contract.Invariant(string.Compare(buffer[i], buffer[i - 1]) >= 0);
}
}
Unfortunately, ccrewrite
is messing up the loops.
The user documentation says that the method should just be a series of calls to Contract.Invariant
. Do I really have to rewrite the code as something like this?
Contract.Invariant(count >= 0 && count <= buffer.Length);
Contract.Invariant(Contract.ForAll
(count, buffer.Length, i => buffer[i] == null));
Contract.Invariant(Contract.ForAll
(1, count, i => string.Compare(buffer[i], buffer[i - 1]) >= 0));
That's somewhat ugly, although it does work. (It's much better than my previous attempt, mind you.)
Are my expectations unreasonable? Are my invariants unreasonable?
(Also asked as a question in the Code Contracts forum. I'll add any relevant answers here myself.)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
从(初步)MSDN 页面来看,Contract.ForAll 成员似乎可以帮助您处理 2 个范围合同。 不过,文档对其功能并不是很明确。
From the (preliminary) MSDN pages it looks like the Contract.ForAll member could help you with the 2 range contracts. The documentation isn't very explicit about its function though.
(我将接受 Henk 的回答,但我认为值得添加这一点。)
该问题现已在 MSDN 论坛,结果是第一个表单无法工作。 不变量确实需要是一系列对
Contract.Invariant
的调用,仅此而已。这使得静态检查器更容易理解不变量并强制执行它。
可以通过简单地将所有逻辑放入不同的成员(例如
IsValid
属性),然后调用来规避此限制:这无疑会弄乱静态检查器,但在某些情况下,它可能是一个在某些情况下有用的替代方案。
(I'm going to accept Henk's answer, but I think it's worth adding this.)
The question has now been answered on the MSDN forum, and the upshot is that the first form isn't expected to work. Invariants really, really need to be a series of calls to
Contract.Invariant
, and that's all.This makes it more feasible for the static checker to understand the invariant and enforce it.
This restriction can be circumvented by simply putting all the logic into a different member, e.g. an
IsValid
property, and then calling:That would no doubt mess up the static checker, but in some cases it may be a useful alternative in some cases.
设计师是不是有点重新发明轮子了?
好旧的出了什么问题
?
现在在 C# 中我们没有 const,但是为什么不能定义一个 Invariant 函数
,然后根据该函数使用代码契约呢?
也许我写的是废话,但即使在这种情况下,当每个人都告诉我错误时,它也会有一些说教价值。
Aren't the designers reinventing the wheel a bit?
What was wrong with the good old
?
Now in C# we don't have const, but why can't you just define an
Invariant
functionand then just use the Code Contracts in terms of that function?
Maybe I'm writing nonsense, but even in that case it will have some didactic value when everybody tells me wrong.