.NET 4特性聚焦:代码契约
去年,我们已经开始在讨论Spec#,这是一个基于C#的支持通过契约来进行设计的语言。以契约来设计是构建于诸如静态类型化这样的概念之上的,特定的动作只有在编译时被验证之后才能执行。契约通常使用前置和后置条件的形式来表示,比如一个参数或返回值永远不能为空或者只能包含某个特定范围的值。
为了不让开发人员学习整个诸如Spec#这样的新语言,微软正在构建一个独立于语言的函数库,可以被任何.NET语言所利用。在某些方面,契约 看上去类似断言,不过它们本质上存在非常大的区别。契约通过静态代码分析的组合来实现,它能被用于编译器内部和外部,以及测试框架之中。它们也能被执行, 这意味着它们在运行调试版本的时候和断言很类似。让我们来看第一个例子:
string GetDescription(int x){
Contract.Requires(x>0);
Contract.Ensures(Contract.Result() != null);
如果只看签名,开发人员只能获得静态类型的信息“GetDescription要求输入一个整数并返回一个字符串”。而通过附加契约,开发人员和工具都可以知道“GetDescription要求输入一个正整数并返回一个不能为空的字符串”。
除了显式的契约之外,契约检查器也支持隐式的契约。一个例子就是被零除这样的情况。如果一个类包含一个整数除法,其中的除数是一个变量,那么所 有的代码路径都必须保证这个变量不会为零或者会引发一个警告。如果在这种情况中的变量是一个开放类的属性,那么它也会要求检查每个子类。对于非关联化空值 和数组索引也存在一些隐式契约。
为了让契约设计更容易,还存在一个ObjectInvariant方法的概念。这个特别的方法只包含契约,可以被注入到每个方法调用的末尾以保证对象的状态保持一致。要着重注意的是,这个东西要应用到所有方法之中,包括那些来自于其他程序集的子类。
另外一个节省时间的功能是轻易对旧值的访问。在下面的例子中,Ensures契约被用于关联OldValue语法以确定集合的数目属性是递增的。
Public Sub Add(value as Object)
Contract.Ensure(Count = Contract.OldValue(Count) + 1)
虽然契约是写在方法之上的,不过它能被编译器自动地移到Return语句之前。由于需要一些系统开销来存储Count的旧值,检查器的这种排序操作只在调试编译版本中发生。
为了支持函数库开发人员,发布版本包含了一个引用程序集。例如,Widgets.dll程序集拥有的大量契约被提取和放置到了程序集Widgets.Contracts.dll中。这允许客户端开发人员在利用由函数库开发人员创建的契约时,还是能使用更快的发布编译版本。
一个更有趣的特性是契约不仅仅能应用于实际的函数,甚至没有其他实现细节的接口和抽象方法也能拥有契约。这是通过创建这个接口的一个引用实现来实现,这个引用实现的唯一目的就是持有契约。而这个引用实现则通过特性以连接回接口。
对于契约的内容没有任何限制。由于相同的契约可以用于静态和运行时检查过程,所以,一个不能被评估的约束可能仍然允许被其他的检查。契约也能被文档生成器提取为文档信息。
关于.NET 4中的契约的更多信息,可以仔细阅读PDC主旨发言的前半部分。
查看英文原文:.NET 4 Feature Focus: Code Contracts
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Android编程实现自定义Dialog的大小自动控制方法示例
- Linux中如何查看文件的创建时间详解
- Android 图片添加水印的实现方法
- Linux系统清除缓存的方法总结
- 详解Android使用@hide的API的方法
- Android 实现按两次返回键退出程序(两种方法)
- 使用 bash 倒计时日期的方法
- Android 实现页面跳转
- Android EditText密码的隐藏和显示功能
- linux系统下的时间配置综述
- Android TextView 去掉自适应默认的fontpadding的实现方法
- Linux文件/目录的权限及归属管理使用
- Android自定义环形LoadingView效果
- Android隐藏标题栏及解决启动闪过标题的实例详解
- Linux使用sed命令替换字符串教程