代码协定(三)——假定和断言

时间:2020-12-06 16:07:36

断言是一种非常常用的契约式编程的手段,自.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吧。