.net 4.0 代码契约-假设vs要求

.net 4.0 代码契约-假设vs要求,.net-4.0,code-contracts,.net 4.0,Code Contracts,这两种说法有什么不同 Contract.Requires(string.IsNullOrWhiteSpace(userName)); Contract.Assume(string.IsNullOrWhiteSpace(userName)); 它只不同于设计时间/静态分析时间 合同。假设: 指示代码分析工具假定指定的条件为真,即使不能静态证明它始终为真 以及: 在运行时,使用此方法相当于使用Assert(Boolean)方法 Requires将保证给定的谓词为true,如果静态代码分析器不能“

这两种说法有什么不同

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

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

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

合同。假设: 指示代码分析工具假定指定的条件为真,即使不能静态证明它始终为真 以及: 在运行时,使用此方法相当于使用Assert(Boolean)方法


Requires将保证给定的谓词为true,如果静态代码分析器不能“证明”事实并非如此,则可能会引发错误。根据合同。假设静态分析器将继续/发出警告/工具将决定的任何内容。

想象您有这样一种方法:

bool ContainsAnX(string s)
{
    return s.Contains("X");
}
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'.");
}
现在,如果将
null
传递给该方法,则该方法将始终失败,因此您希望确保这种情况永远不会发生。这就是
合同所要求的。它为方法设置了一个前提条件,该前提条件必须为true才能正确运行方法。在这种情况下,我们将:

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

    return s.Contains("X");
}   
注意
要求
并确保
必须始终位于方法的开头,因为它们是关于整个方法的信息。
假设
用于代码本身,因为它是关于代码中该点的信息。)

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

bool ContainsAnX(string s)
{
    return s.Contains("X");
}
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(或者永远不应该返回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'.");
}
现在,使用静态检查器就可以了。如果启用了运行时契约,则在运行时也将检查该假定

您可能需要假设的另一种情况是,前提条件非常复杂,静态检查器很难证明它们。在这种情况下,您可以稍微推一下它,帮助它前进:)

就运行时行为而言,使用“假定”和“要求”之间没有太大区别。然而,使用静态检查器的结果会有很大的不同。在故障情况下谁对错误负责方面,每一项的含义也不同:

  • Requires意味着调用此方法的代码必须确保条件成立
  • 假设意味着此方法所做的假设应始终为真
根据:第7页(前提条件)和第11页(假设条件)

要求:

  • 是一个先决条件(“先决条件是通过使用Contract.Requires导出的”)
  • 作为先决条件,将在方法调用时执行
假设:

  • 不是先决条件,不是后决条件,不是不变量
  • 在指定点执行
  • “仅当定义了完整合同符号或调试符号时,才存在于生成中”
假设和要求做根本不同的事情。非常好的解释!但有一个问题。你所说的“静态检查器”是什么意思。我使用的是VS专业版。静态检查器是一个程序,它试图在编译时验证所有契约是否正确。不幸的是,目前它仅适用于VS2010高级版或终极版。静态检查器现在可用于所有级别的Visual Studio(当然,除Express外)。