在对象不变量的代码中我可以有多自由?

发布于 2024-07-29 22:34:19 字数 1343 浏览 5 评论 0原文

我试图演示代码契约中的不变量,并且我想我应该给出一个排序的字符串列表的示例。 它在内部维护一个数组,并具有用于添加等的备用空间 - 基本上就像 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

情徒 2024-08-05 22:34:19

从(初步)MSDN 页面来看,Contract.ForAll 成员似乎可以帮助您处理 2 个范围合同。 不过,文档对其功能并不是很明确。

//untested
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));

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.

//untested
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));
童话里做英雄 2024-08-05 22:34:19

(我将接受 Henk 的回答,但我认为值得添加这一点。)

该问题现已在 MSDN 论坛,结果是第一个表单无法工作。 不变量确实需要是一系列对 Contract.Invariant 的调用,仅此而已。

这使得静态检查器更容易理解不变量并强制执行它。

可以通过简单地将所有逻辑放入不同的成员(例如 IsValid 属性),然后调用来规避此限制:

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:

Contract.Invariant(IsValid);

That would no doubt mess up the static checker, but in some cases it may be a useful alternative in some cases.

何以心动 2024-08-05 22:34:19

设计师是不是有点重新发明轮子了?

好旧的出了什么问题

bool Invariant() const; // in C++, mimicking Eiffel

现在在 C# 中我们没有 const,但是为什么不能定义一个 Invariant 函数

private bool Invariant()
{
  // All the logic, function returns true if object is valid i.e. function
  // simply will never return false, in the absence of a bug
}
// Good old invariant in C#, no special attributes, just a function

,然后根据该函数使用代码契约呢?

[ContractInvariantMethod]
private void ObjectInvariant()
{
    Contract.Invariant(Invariant() == true);
}

也许我写的是废话,但即使在这种情况下,当每个人都告诉我错误时,它也会有一些说教价值。

Aren't the designers reinventing the wheel a bit?

What was wrong with the good old

bool Invariant() const; // in C++, mimicking Eiffel

?

Now in C# we don't have const, but why can't you just define an Invariant function

private bool Invariant()
{
  // All the logic, function returns true if object is valid i.e. function
  // simply will never return false, in the absence of a bug
}
// Good old invariant in C#, no special attributes, just a function

and then just use the Code Contracts in terms of that function?

[ContractInvariantMethod]
private void ObjectInvariant()
{
    Contract.Invariant(Invariant() == true);
}

Maybe I'm writing nonsense, but even in that case it will have some didactic value when everybody tells me wrong.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文