代码契约——当我使用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.
方法的问题在于,当您调用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) >= 0
0作为示例。
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);
}
并且类似地用于其它类型。