【问题标题】:Code Contracts and type conversion代码契约和类型转换
【发布时间】:2009-10-31 06:53:42
【问题描述】:

我尝试使用 Microsoft DevLabs Code Contracts 静态分析器,但遇到了我实际上不知道是我还是他们的情况。所以这里是代码:

    public static int GenerateInBetween(int min, int max)
    {
        Contract.Requires(min < max);
        Contract.Requires((long)(max - min) <= (long)(Int32.MaxValue));

        Contract.Ensures(Contract.Result<int>() >= min);
        Contract.Ensures(Contract.Result<int>() <= max);  // Unpvoven!

        long range = max - min;

        double basicRandom = new Random().NextDouble();
        Contract.Assert(basicRandom >= 0.0);
        Contract.Assert(basicRandom <= 1.0);              // Unpvoven!

        double randomDouble = basicRandom * range;
        Contract.Assert(randomDouble >= 0.0);
        Contract.Assert(randomDouble <= (double)range);   // Unpvoven!

        int randomInt32 = (int)randomDouble;
        Contract.Assert(randomInt32 >= 0);
        Contract.Assert(randomInt32 <= range);

        return min + randomInt32;
    }

静态分析器坚持认为无法证明已评论的后置条件和断言。我看不出什么时候会出错。

编辑即使我将断言替换为假设后置条件仍然未经证实。

【问题讨论】:

  • 已经有一个System.Random.Next(int min, int max) 方法。但 max 参数是一个排他性的上限。
  • 谢谢。为了方便起见,我插入了 System.Random.Next() 调用。我在那个地方使用 crypt-strong 随机算法,但无论哪种方式都会出现问题。

标签: c# .net code-contracts


【解决方案1】:

好的,我最初以为我可以将它分成两部分,但意识到我的第一个答案实际上并没有回答真正的问题。

这是您问题的最短版本:

    public static void GenerateInBetween(double min, double max)
    {
        Contract.Requires(min < max);
        double range =  max - min;

        double randomDouble = 1.0 * range;
        Contract.Assert(randomDouble <= range);   
    }

正如另一位评论者所提到的,如果您将硬编码的 1.0 更改为值

但是,如果您删除 Contract.Requires(min

抱歉,目前我对此没有任何解释。

【讨论】:

  • 感谢马特的研究。我也有同样的结局。静态检查器的那一部分出了点问题,现在我很确定情况确实如此,因为您已经独立得出了这个结论。我现在将对该文件进行静态验证。
【解决方案2】:

我尝试了您的示例并尝试将其归结为最基本的示例。

似乎可能存在一些问题,但我认为这里有一个例子可以说明一个主要问题:

public static void TestMethod()
{
    double d = MethodReturningDouble();
    Contract.Assert(d >= 0.0);
    Contract.Assert(d <= 4.0);
}

public static double MethodReturningDouble()
{
  //  Contract.Ensures(Contract.Result<double>() <= 4.0); // <- without this line the above asserts are unproven
    return 3.0;
}

如果没有调用方法的代码契约规范,静态检查器/分析器似乎无法解决任何其他问题。 MethodReturningDouble() 返回一个常量,静态检查器无法确定断言将始终通过。

总之,静态分析器似乎用于代码合约规范,而不用于一般分析。

可以添加关于您调用的方法的假设(没有定义合同):

例如:

public static void TestMethodUsingRandom()
{
    double d = new Random().NextDouble();
    Contract.Assume(d <= 1.0);

    Contract.Assert(d >= 0.0);
    Contract.Assert(d <= 4.0);
}

如果您确定特定方法以特定方式运行,则这样做是合法的。

【讨论】:

  • 来自代码合同页面“cccheck,一个在编译时验证合同的静态检查器。” - 这似乎支持验证器仅用于验证合同的结论。 research.microsoft.com/en-us/projects/contracts
  • 除非我弄错了,Artem 已经尝试将 Assert 更改为 Assume。如果没有,我有,但这并不能解决问题。如果您将 basicRandom 变量更改为硬编码为 0.5 的任何值(例如 0.5000001)并且无法验证它。这让我觉得这里发生了一些我看不到的更微妙的事情。无论如何,我很想知道发生了什么!
  • 是的,我刚刚意识到这一点。我添加了另一个以最小形式呈现问题的答案。
  • 好吧,这很奇怪——我的更新版本没有出现 0.5 的问题。我会重新检查我的假设。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多