代码合同和类型转换

时间:2009-10-31 06:53:42

标签: c# .net code-contracts

我试图接受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;
    }

静态分析器坚持认为无法证明评论后的条件和断言。我看不出它何时出错。

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

2 个答案:

答案 0 :(得分: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更改为值<= 0.5,则它会通过检查。如果是> 0.5然后它失败了。

但是,如果你删除Contract.Requires(min&lt; max)行,那么它总是会失败。

我暂时没有这方面的解释,抱歉。

答案 1 :(得分:0)

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

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

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

如果您确定某个特定方法以特定方式运行,那么这是合法的事情。