代码契约

代码契约之于C#语言,就相当于诗歌之于自然语言。
代码契约能从根本上改变代码的外观和所传达的信息量。
——《深入理解C#》(第二版)

Code Contract for .NET

使用之前必须先安装Code Contract for .NET,可以在

https://visualstudiogallery.msdn.microsoft.com/1ec7db13-3363-46c9-851f-

1ce455f66970下载,安装之后visual studio的项目属性页中多了一页“Code
Contract”。

无标题

代码契约类型

前置条件

前置条件(Precondition)是对方法调用者提出要求,而不是表示普通条件下方法本身
的行为。我们总是坚信自己的代码没有问题,但却不能信任外部代码,因此前置条件是
已有程序中最常见的契约代码。前置契约使用Requires方法实现。

 C# Code
1
2
3
4
5
 

public static double Sqrt(double x)

{

Contract.Requires(x >= 0);

return Math.Sqrt(x);

}

如果你在一个公共public方法中,对一个私有private变量使用前置条件契约,编译器会
直接报错,因为这样做对调用者是不公平的。

后置条件

前置条件是对方法输入或对象的原始状态的约束,而后置条件(Postcondition)是对方
法输出的约束:返回值、out或ref参数的值,以及任何被改变的状态。后置条件使用
Ensures方法实现。

 C# Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 
class  MyTest
{
    int  m_nState =  0 ;
    //检查返回值。
     public   int  Func1( int  x)
{
Contract.Ensures(Contract.Result<
int >() >  0 );
m_nState–;
        return  x *  5 ;
}
    //检查out参数,ref参数方法一样。
     public   void  Func2( int  x,  out   int  y)
{
Contract.Ensures(Contract.ValueAtReturn<
int >( out  y) >  0 );
m_nState++;
y = x * 
3 ;
}
    //检查本地状态
     public   int  Func3( int  x)
{
Contract.Ensures(Contract.ValueAtReturn<
int >( out
m_nState) > 
0 );
        return  x +  1 ;
}
}

后置条件的实现需要Contract.Result<T>()和Contract.ValueAtReturn<T>两个方法配
合实现。
后置条件最神奇的地方是契约代码写在return语句之前,可以省去定义一个临时变量存
放要返回的值,再对这个临时变量进行检查(手工断言)。这是代码契约与手工断言之
间最重要的区别。

固定条件/对象不变量

尽管叫invariant,但它并不表示一个保持不变的值,而是表示一个总是满足的固定条件
。例如一个字符串变量,在它可以在对象的生命周期内被不断修改,但永远满足不为空
的条件。固定条件可以在任何方法结束时进行自动检测,而不毕为防止出错,在每个方
法结束时对该变量进行检测。
固定条件的使用必须顶一个检测方法:必须是私有方法Private,必须用
ContractInvariantMethod特性修饰。

 C# Code
1
2
3
4
5
 

[ContractInvariantMethod]

private void CheckState()

{

Contract.Invariant(m_nState > -10 && m_nState < 10);

}

断言和假设

Assert和Assume,如果不使用静态检查器,二者没有区别,它们和Debug.Assert方法类
似,在执行时检查某个条件是否为真。静态检查器处理这二个方法时略有不同,他会检
验断言是否为真,却不会处理假设。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 
public   int  RollDice(Random rng)
{
Contract.Ensures(Contract.Result<
int >() >=  2 );
Contract.Ensures(Contract.Result<
int >() <=  12 );Contract.Assert(rng != null );

int  firstRoll = rng.Next( 1 7 );
Contract.Assume(firstRoll >= 
1 );
Contract.Assume(firstRoll <= 
6 );
int  seconfRoll = rng.Next( 1 7 );
Contract.Assume(seconfRoll >= 
1 );
Contract.Assume(seconfRoll <= 
6 ); return  firstRoll + seconfRoll;
}
转载自 开开博客

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值