位置:海鸟网 > IT > ASP.NET >

.NET 4.0 中的契约式编程

契约式编程不是一门崭新的编程方法论。C/C++ 时代早已有之。Microsoft 在 .NET 4.0 中正式引入契约式编程库。博主以为契约式编程是一种相当不错的编程思想,每一个开发人员都应该掌握。它不但可以使开发人员的思维更清晰,而且对于提高程序性能很有帮助。值得一提的是,它对于并行程序设计也有莫大的益处。

我们先看一段很简单的,未使用契约式编程的代码示例。

{ { { CheckInvariant(T& argument){.numberator = numberator; CONTRACT_FULL }("The argument can not be null.");Contract.EndContractBlock(); // 前面所有的 if 检测语句皆是 Preconditions 契约

这种 Preconditions 契约的格式严格受限:它必须严格按照上述代码示例格式。而且不能有 else 从句。此外,then 从句也只能有单个 throw 语句。最后必须使用 Contract.EndContractBlock() 方法来标记 Preconditions 契约结束。

看到这里,是不是觉得大多数参数验证都可以被 Preconditions 契约替代?没有错,事实的确如此。这样这些防御性代码完全可以在 Release 被去掉,从而不用做那些冗余的代码检测,从而提高程序性能。但在面向验证客户输入此类情境下,防御性代码仍有必要。再就是,Microsoft 为了保持兼容性,并没有用 Preconditions 契约代替异常。

4. Postconditions

Postconditions 契约表示方法终止时的状态。它跟 Preconditions 契约的运行时行为完全一致。但与 Preconditions 契约不同,Postconditions 契约相关的成员有着更少的可见性。客户程序或许不会理解或使用 Postconditions 契约表示的信息,但这并不影响客户程序正确使用 API 。

对于 Preconditions 契约来说,它则对客户程序有副作用:不能保证客户程序不违反 Preconditions 契约。

A. 标准 Postconditions 契约用法

.NET 4.0 使用 Contract.Ensures() 方法表示标准 Postconditions 契约用法。它表示方法正常终止时必须保持的契约。

Contract.Ensures(this.F > 0);B. 特殊 Postconditions 契约用法

当从方法体内抛出一个特定异常时,通常情况下 .NET CLR 会从方法体内抛出异常的位置直接跳出,从而辗转堆栈进行异常处理。假如我们需要在异常抛出时还要进行 Postconditions 契约验证,我们可以如下使用:

Contract.EnsuresOnThrows<T>(this.F > 0);

其中小括号内的参数表示当异常从方法内抛出时必须保持的契约,而泛型参数表示异常发生时抛出的异常类型。举例来说,当我们把 T 用 Exception 表示时,无论什么类型的异常被抛出,都能保证 Postconditions 契约。哪怕这个异常是堆栈溢出或任何不能控制的异常。强烈推荐当异常是被调用 API 一部分时,使用 Contract.EnsuresOnThrows<T>() 方法。