代码合同 - 当我使用IComparable或IComparable时需要/确保未经证实<t> </t>

时间:2012-02-25 16:21:32

标签: c# generics require code-contracts icomparable

我有以下方法:

public static bool IsBetween<T>(this IComparable<T> value, T lowerBound, T upperBound)
    where T : IComparable<T>
{
    Contract.Requires<>(value != null);
    Contract.Requires<>(lowerBound != null);
    Contract.Requires<>(upperBound != null);
    Contract.Requires<>(upperBound.CompareTo(lowerBound) >= 0);

    return IsBetween(value, lowerBound, upperBound, InclusionOptions.None);
}

public static bool IsBetween<T>(this IComparable<T> value, T lowerBound, T upperBound,
     InclusionOptions options) where T : IComparable<T>
{
    Contract.Requires<>(value != null);
    Contract.Requires<>(lowerBound != null);
    Contract.Requires<>(upperBound != null);
    Contract.Requires<>(upperBound.CompareTo(lowerBound) >= 0); //Code Contracts Issue

    ...
}

这里的问题是它不喜欢我的上一个要求。它声明CodeContracts: requires unproven: upperBound.CompareTo(lowerBound) >= 0。我不太确定在这里解决这个问题的正确方法。我需要确保当我执行比较值时,我实际上有一个真正的lowerBound和upperBound值,并且lowerBound值不高于upperBound值。

哦,我不能使用实际的&lt;或者&gt;运算符,因为您无法将它们应用于“T”类型。


最后,我知道可以是一个单独的问题,但它是高度相关的......如果有人知道为什么我在使用Code Contracts v1.4.50126时仍然会收到CA1062代码分析错误。 1请告诉我如何解决问题:CA1062: Microsoft.Design : In externally visible method 'MyClass.IsBetween<T>(this IComparable<T>, T, T), validate parameter 'upperBound' before using it.

2 个答案:

答案 0 :(得分:0)

您的方法的问题在于,当您调用upperBound.CompareTo时,您假设编译器知道类型T(这是upperBound参数的声明类型)实现IComparable<T>接口(声明CompareTo方法)。

通常情况(按照惯例)IComparable<T>接口将由类型T实现(如果有的话);但是,除非您通过类型约束明确指定它,否则编译器不会知道它。

public static bool IsBetween<T>(this T value, T lowerBound, T upperBound)
    where T : IComparable<T>
{
    Contract.Requires(value != null);
    Contract.Requires(lowerBound != null);
    Contract.Requires(upperBound != null);
    Contract.Requires(upperBound.CompareTo(lowerBound) >= 0);

    // ...
}

答案 1 :(得分:0)

我将以int为例。

int.CompareTo(int)的合同无法确保任何特定的返回值。 知道如果a >= b,那么a.CompareTo(b) >= 0,但由于这没有被表达为合同,静态检查员唯一看到的是“a.CompareTo(b)返回一个int“。 “一个int”不能被证明是非负的。

您应该可以添加类似

的内容
Contract.Assert(a >= b);
Contract.Assume(a.CompareTo(b) >= 0);

在你称之为功能的地方。这使静态检查器首先尝试证明a >= b并通知您是否无法证明这一点,然后相信您已满足功能要求。

如果您经常为int调用此函数,则可能需要使用此修改后的int特定合同创建包装函数:

public static bool IsBetween(this int value, int lowerBound, int upperBound)
{
    Contract.Requires<>(value != null);
    Contract.Requires<>(lowerBound != null);
    Contract.Requires<>(upperBound != null);
    Contract.Requires<>(upperBound >= lowerBound);
    Contract.Assume(upperBound.CompareTo(lowerBound) >= 0);
    return IsBetween<int>(value, lowerBound, upperBound);
}

和其他类型相似。