代码契约

来源:互联网 发布:mac如何修改登录密码 编辑:程序博客网 时间:2024/04/28 00:43

代码契约之于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(17);
Contract.Assume(firstRoll >= 
1);
Contract.Assume(firstRoll <= 
6);
int seconfRoll = rng.Next(17);
Contract.Assume(seconfRoll >= 
1);
Contract.Assume(seconfRoll <= 
6);return firstRoll + seconfRoll;
}
转载自开开博客

0 0
原创粉丝点击