代码合同 - 假设与要求

时间:2011-01-21 11:51:41

标签: .net-4.0 code-contracts

这两个陈述之间有什么区别?

Contract.Requires(string.IsNullOrWhiteSpace(userName));

Contract.Assume(string.IsNullOrWhiteSpace(userName));

3 个答案:

答案 0 :(得分:63)

想象一下,你有一个像这样的方法:

bool ContainsAnX(string s)
{
    return s.Contains("X");
}

现在,如果您将null传递给它,此方法将始终失败,因此您希望确保此方法永远不会发生。这是Contract.Requires的用途。它为方法设置了前提条件,必须为true才能使方法正确运行。在这种情况下,我们会:

bool ContainsAnX(string s)
{
    Contract.Requires(s != null);

    return s.Contains("X");
}   

注意RequiresEnsures必须始终位于方法的开头,因为它们是有关整个方法的信息。Assume在代码本身中使用,因为它是关于代码中该点的信息。)

现在,在调用方法“ContainsAnX”的代码中,必须确保字符串不为null。您的方法可能如下所示:

void DoSomething()
{
    var example = "hello world";

    if (ContainsAnX(example))
        Console.WriteLine("The string contains an 'X'.");
    else
        Console.WriteLine("The string does not contain an 'X'.");
}

这样可以正常工作,静态检查器可以证明example不为空。

但是,您可能正在调用外部库,这些库没有关于它们返回的值的任何信息(即它们不使用代码约定)。让我们改变一下这个例子:

void DoSomething()
{
    var example = OtherLibrary.FetchString();

    if (ContainsAnX(example))
        Console.WriteLine("The string contains an 'X'.");
    else
        Console.WriteLine("The string does not contain an 'X'.");
}

如果OtherLibrary不使用代码合同,静态检查器会抱怨example可能为空。

也许他们的库文档说该方法永远不会返回null(或者应该永远不会!)。在这种情况下,我们知道的不仅仅是静态检查器,因此我们可以告诉它 Assume 变量永远不会为null:

void DoSomething()
{
    var example = OtherLibrary.FetchString();

    Contract.Assume(example != null);

    if (ContainsAnX(example))
        Console.WriteLine("The string contains an 'X'.");
    else
        Console.WriteLine("The string does not contain an 'X'.");
}

现在静态检查器可以正常使用。如果启用了运行时契约,则还将在运行时检查Assume。

您可能需要假设的另一种情况是,您的前置条件非常复杂且静态检查器很难证明它们。在这种情况下,你可以给它一点点推动来帮助它:)

就运行时行为而言,使用Assume和Requires之间没有太大区别。但是,静态检查器的结果会有很大差异。每个人的意思也是不同的,就谁在失败的情况下对错误负责而言:

  • 需要表示调用此方法的代码 必须确保条件成立。
  • 假设此方法正在做出一个应该始终成立的假设。

答案 1 :(得分:2)

它只有不同的设计时/静态分析时间

Contract.Assume: “指示代码分析工具假设指定的条件为真,即使它不能被静态证明永远是真的” 和: 在运行时,使用此方法相当于使用Assert(布尔)方法。

Contract.Requires将保证给定谓词为真,如果静态代码分析器无法“证明”不是这种情况,则可能会引发错误。在Contract.Assume静态分析器将继续/发出警告/工具将决定的任何内容。

答案 2 :(得分:0)

根据official documentation:第7页(前置条件)和第11页(假设)。

<强>需要:

  • 是一个先决条件(“使用Contract.Requires取消前置条件”);
  • 作为前提条件将在方法调用上执行;

<强>假设:

  • 不是先决条件,不是后置条件,不是不变量;
  • 在指定的位置执行;
  • p. 11“只有在定义了全合同符号或DEBUG符号时才存在于构建中”;