以下是Pex文档中的代码示例pexandcontracts.pdf http://research.microsoft.com/en-us/projects/pex/pexandcontracts.pdf。我意识到这不是一个特定于pex的问题,而是与代码契约有关,但它是来自pex教程的代码。
namespace CodeDigging
{
public class StringExtension
{
public static string TrimAfter(string value, string suffix)
{
// <pex>
Contract.Requires(!string.IsNullOrEmpty(suffix));
// </pex>
Contract.Requires(value != null);
Contract.Ensures(!Contract.Result<string>().EndsWith(suffix));
int index = value.IndexOf(suffix);
if (index < 0)
return value; // (1) First possible contract violation
return value.Substring(0, index); // (2) second possible contract violation
}
}
}
静态验证程序提供以下警告:
CodeContracts:确保未经证实:!Contract.Result()。EndsWith(后缀)在第(1)点和第(2)点。
我的问题是,如何解决这个问题呢?根据pex探索,合同不可能被违反。 (......有吗?)
答案 0 :(得分:3)
我认为这是对Contract.Ensures的一种不良使用,因为保证相当复杂,并且不太可能随时提供给后来的需求。我更倾向于提供非无效性和长度的保证(即不超过原始值字符串。)!EndsWith条件应该是测试的断言,Pex可以使用它来指导其探索。
答案 1 :(得分:2)
最好的办法是在静态检查程序无法验证表达式时使用Contract.Assume
。
如果你试图获得零静态检查器警告,你将最终得到许多你需要使用Contract.Assume
的地方,除非你的程序是微不足道的,因为大多数.Net库都没有但是我有合同所以我不担心。大部分时间都有明确的代码和一组良好的单元测试比没有合同警告要好。也就是说,留下波浪线,以便在编码时验证警告是误报。
答案 2 :(得分:0)
是的,有可能违反合同。请记住,IndexOf
和EndsWith
默认情况下使用特定于文化的比较,这有时可能会产生令人惊讶的行为。如果我写
TrimAfter("\u0301a\u0301a", "\u0301a")
然后IndexOf
与第一次出现不匹配,因为它认为中间字符是单个'á'
,因此index
是2
,方法返回{{ 1}},显然以后缀结尾。
如果您需要可证明正确的算法,请使用"\u0301a"
。
但是,Code Contracts静态检查器目前不支持对字符串值进行分析,也不理解StringComparison.Ordinal
和IndexOf
之间的这种关系。