代码契约——当我使用IComparable或IComparable<;T>;

本文关键字:IComparable lt gt 契约 代码 | 更新日期: 2023-09-27 18:25:51

我有以下方法:

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
    ...
}

这里的问题是它不喜欢我的最后一个要求。它表示CCD_ 1。我真的不确定在这里解决这个问题的正确方法。我需要确保当我进行比较值时,我实际上有一个真正的lowerBound和upperBound值,并且lowerBoud值不高于upperBourd值。

哦,我不能用实际的<或者>运算符,因为无法将它们应用于类型"t"。


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

代码契约——当我使用IComparable或IComparable<;T>;

方法的问题在于,当您调用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);
    // ...
}

我将使用CodeContracts: requires unproven: upperBound.CompareTo(lowerBound) >= 00作为示例。

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

并且类似地用于其它类型。