"不包含空格"在代码合同?

时间:2015-02-13 16:41:17

标签: c# .net code-contracts

我是代码合约的新手 - 刚刚开始尝试解决这个问题。我刚碰到了一些我不确定如何完成的事情:

我有一个私人的readonly字段,可以公开"得到"通过财产:

private readonly string name;
public string Name
{
    get
    {
        return this.name;
    }
}

此字段永远不应为null,永远不应为空,并且绝不应包含任何空格。所以我把各种各样的"要求"进入构造函数以尝试确保这些事情:

public Thing(string name)
{
    Contract.Requires<ArgumentNullException>(
        name != null, 
        "Name must not be null");
    Contract.Requires<ArgumentException>(
        name.Length > 0,
        "Name must have positive length");
    Contract.Requires<ArgumentException>(
        !name.Any(x => char.IsWhiteSpace(x)),
        "Name must not include whitespace");

    this.name = name;
}

使用一些代码来试图违反这些合同,这表明静态检查程序成功捕获了违反&#34; not null&#34;并且&#34;不是空的&#34;,但它没有捕获违反&#34;不包含空格&#34;。我想这不足为奇?我想它在编译时会进行某些简单的检查(例如&#34;!= null&#34;)但是其他更复杂的检查(比如空格的linq检查)除了可能在运行时之外都没有完成?

无论如何,我在课堂上添加了一些不变量来试图描述这些相同的东西:

[ContractInvariantMethod]
private void ContractInvariants()
{
    Contract.Invariant(this.name != null);
    Contract.Invariant(this.name.Length > 0);
    Contract.Invariant(!this.name.Any(x => char.IsWhiteSpace(x)));
}

这导致我的构造函数(上面引用)发出以下警告(至少警告级别设置为高):

CodeContracts: invariant unproven: !this.name.Any(x => char.IsWhiteSpace(x))

但是构造函数将this.name设置为需要相同合同的局部变量的值!

我的要求和/或我的不变量没有做我打算做的事吗?有没有办法让他们做我打算做的事情?我是否应该首先尝试让他们做我打算做的事情?我只是从根本上误解了这里的事情吗?就像我说的,我对此完全陌生。感谢您提供任何指导。

2 个答案:

答案 0 :(得分:1)

代码合同旨在通过推理来证明关于需要确保在编译时的假设。但是这个问题是不可判定的,因此不可能对所有内容进行验证(即使是在数千年内发明的技术,也从根本上证明 - 不可能)。然而,保守算法可以证明这些陈述的一部分,并警告程序员它无法证明其他或证明合同会受到损害。

您的不变量存在一些问题,您在其中调用 Linq 方法,并且可能 Linq 方法不提供(必要的)代码合同本身来执行推理得当。您不必为所有方法提供合同。系统有时能够自己推理代码和理由。但不总是。例如,数组列表的代码不一定表明Count总是大于或等于零...

然而,

代码契约有一些内置函数可以处理像Contract.ForAll函数这样的集合:

Contract.Invariant(
    Contract.ForAll(this.name, x => !char.IsWhiteSpace(x))
);

这有更多机会获得验证,但同样,不能保证这会有太大变化。代码合同既不会得到证实,也不会被证明是错误的。

答案 1 :(得分:0)

您应该使用Contract.Invariant(!string.IsNullOrWhitespace(value))代替。它将同时涵盖所有三种情况,CodeContract引擎也可以在编译时支持它。