这两个陈述之间有什么区别?
Contract.Requires(string.IsNullOrWhiteSpace(userName));
Contract.Assume(string.IsNullOrWhiteSpace(userName));
答案 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");
}
(注意:Requires
和Ensures
必须始终位于方法的开头,因为它们是有关整个方法的信息。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页(假设)。
<强>需要:强>
<强>假设:强>