我正在玩代码契约,并得到一个简单的方法,在每个字符之间插入一定数量的空格字符。
e.g。
Hello -> H e l l o
World -> W o r l d
InsertSpaceBetweenLetters方法是在一个提供一些字符串属性S的类中实现的,该字符串属性应该是修改后返回的字符串。这是代码
public string InsertSpaceBetweenLetters(int spaceWidth)
{
Contract.Requires(spaceWidth > 0);
Contract.Requires(S.Length > 0);
Contract.Ensures(Contract.Result<string>() != null);
Contract.Ensures(Contract.Result<string>().Length == S.Length + (S.Length - 1) * spaceWidth);
string result = String.Empty;
Contract.Assume(S.Length >= 0);
for(int i = 0; i < S.Length; i++)
{
result += S[i];
if (i < S.Length - 1)
result += new String(' ', spaceWidth);
}
return result;
}
静态检查器给出了以下警告:
ensures unproven: Contract.Result<string>().Length == S.Length + (S.Length - 1) * spaceWidth
我以为我可以在循环之前做的假设中摆脱这个警告:
Contract.Assume(S.Length >= 0);
但警告仍在那里。必须做出哪些假设才能摆脱警告?
提前谢谢。
答案 0 :(得分:3)
从根本上说,我认为你在这种情况下要求过多的静态检查器。如果真的可以工作那将是非常令人印象深刻的。在这种情况下,我认为你只需要将它作为执行时检查而不是编译时检查。
我不知道是否有一种特定的说法“请确保这是一个后置条件,但不要试图证明这一点” - 用后置条件呼叫Contract.Assume
/ em>在方法的最后可以这样做,但它可能意味着评估它两次:(
(顺便说一下,你的实现目前真的效率低下。这不是这个问题的主题,但仍然值得一看。)
答案 1 :(得分:1)
我认为你的假设是错误的。它不适用于S.Length == 0
:在第二个ensures
中,您会得到一个否定值。
其次,在编译时检查ensures
语句并非易事。可能只是没有在检查器中实现..
也许你可以用不同的方式实现你的循环。删除if
语句并从0循环到S.Length-2。但我不确定..
答案 2 :(得分:0)
试试这个
public string InsertSpaceBetweenLetters(string S, int spaceWidth) {
Contract.Requires(spaceWidth > 0);
Contract.Requires(S != null);
Contract.Requires(S.Length > 0);
Contract.Ensures(Contract.Result<string>() != null);
Contract.Ensures(Contract.Result<string>().Length == S.Length + (S.Length - 1) * spaceWidth);
StringBuilder result = new StringBuilder(String.Empty);
int count = 0;
int final = S.Length - 1;
foreach ( char c in S )
{
result.Append(c, 1);
if ( count < final )
{
result.Append(' ', spaceWidth);
}
++count;
}
return result.ToString();
}