代码合同:确保字符串方法未经证实

时间:2012-11-21 10:55:02

标签: c# code-contracts specifications

我正在玩代码契约,并得到一个简单的方法,在每个字符之间插入一定数量的空格字符。

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);

但警告仍在那里。必须做出哪些假设才能摆脱警告?

提前谢谢。

3 个答案:

答案 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();
    }