断言是一种非常常用的契约式编程的手段,自.Net 1.0起就内置了对断言的支持,使用方式如下:
Debug.Assert(offset == 10);
在Code Contract中,也提供了对断言的支持,不过将其进一步细化了为假定和断言两种API:
Contract.Assert(offset == 10);
Contract.Assume(offset == 10);
这两种API的使用方式和功能大体上Debug.Assert和非常类似,从API上基本上看不出来它们的分别。实际上,他们的区别主要是在于对静态代码分析(在后面的文章中介绍)的条件上,Contract.Assert上比Contract.Assume更加严格。例如,对于如下函数:
public static int CalculateSomeValues()
{
return 1;
}
static void Main(string[] args)
{
int x = CalculateSomeValues();
Contract.Assert(x > 0);
}
开启了静态检查后,会发现Contract.Assert会报告警:(用Contract.Assume则没有这个告警)
这个告警的意思是无法保证CalculateSomeValues函数返回值大于0,要消除这个告警,则需要在CalculateSomeValues函数里加一个后置条件约定:
public static int CalculateSomeValues()
{
Contract.Ensures(Contract.Result<int>() >0);
return 1;
}
不过,这也是一个非常苛刻的检查了,只有把静态检查开关开得很大才会出现这个告警,大多数的情形下是不会有这个告警的。可能微软也觉得严格执行全流程约定反而会使代码协定成为负担,有些舍本逐末了。也就是说,大部分的时候,这两个API并没有什么大的区别。
另外,微软官方给Contract.Assume定义了一个快捷键"cam",并没有找到Contract.Assert。可能微软官方貌似也是推荐使用Contract.Assume吧。