.NET的Contract类库是Declarative Programming实践的一部分,可以对日常编程带来很多好处:

  • 提高代码可读性,使用者一看Require, Ensure就知道这方法接受什么输入,产生什么输出。
  • 减少重复的验证代码
  • 配合第三方工具,可以方便静态代码分析和单元测试,方便产生API文档,这些功能可以参见Code Contract主页

Contract类本身已经在.NET 4.0之后集成进了System.Diagnostics.Contracts命名空间,但如果想使用Contract方法实现运行时的验证,还需要单独安装一个VS插件。装好之后,去项目属性里开启运行时检查:

这样每次编译项目的时候,插件里的ccrewrite工具会将Contract方法编译成有效的检查代码分别注入函数体的首尾。所以即使你把Contract.Ensures检查放在函数开头部分(这也是推荐做法),编译之后这部分逻辑依然会出现在函数末尾,检查函数结束条件是否满足。

需要注意的是,如果想要在Debug和Release Build都使用运行时验证功能,则需要在项目设置为Debug和Release编译时,分别设置打开Runtime check。

Contract的基本使用包括Requires和Ensures,Requires在方法开始时检查初始条件是否满足,通常用来做参数验证。Ensures方法用来在方法结束时检查执行结果是否符合预期,比如可以放在Property set方法的末尾检查Property是否被正确设置。

当检查失败时,默认会抛出ContractException,使用泛型的Requires和EnsuresOnThrow可以指定其他类型的异常。

        public async void GetPage(string entryPageUrl)
{
Contract.Requires<ArgumentException>(Uri.IsWellFormedUriString(entryPageUrl, UriKind.Absolute));
...
}

Contract有一个很酷的feature,就是可以在接口里定义一些检查,要求所有的实现都满足这些检查条,这样就不用在接口的每个实现里分别定义相同的检查逻辑了,非常的优雅,也符合Declaration Programming的初衷。

以下是示例代码:

    [ContractClass(typeof(IBookRepositoryContract))]
public interface IBookRepository
{
string BookTitle { get; set; }
void Create(string name, Stream blob);
} [ContractClassFor(typeof(IBookRepository))]
sealed class IBookRepositoryContract : IBookRepository
{
public string BookTitle
{
get
{
return null;
}
set
{
Contract.Requires(!string.IsNullOrWhiteSpace(value), "Book title must not be empty.");
Contract.Requires(string.IsNullOrWhiteSpace(this.BookTitle), "Book title has already been set.");
}
} public void Create(string name, Stream blob)
{
Contract.Requires<InvalidOperationException>(!string.IsNullOrWhiteSpace(this.BookTitle), "Book title hasn't been set");
}
}

这样所有IBookRepository的实现类都无需再定义这些检查了。

参考资料:

http://research.microsoft.com/en-us/projects/contracts/userdoc.pdf

http://blog.csdn.net/atfield/article/details/4465227

http://www.cnblogs.com/yangecnu/p/The-evolution-of-argument-validation-in-DotNet.html

利用.NET Code Contracts实现运行时验证的更多相关文章

  1. 【翻译】利用Qt设计师窗体在运行时创建用户界面(Creating a user interface from a Qt Designer form at run-time)

    利用Qt设计师窗体在运行时创建用户界面 我们利用Calculator窗体例子中创建的窗体(Form)来展示当一个应用(application)已经生成后,是可以在其运行时产生与例子中相同的用户界面. ...

  2. C/C++杂记:运行时类型识别(RTTI)与动态类型转换原理

    运行时类型识别(RTTI)的引入有三个作用: 配合typeid操作符的实现: 实现异常处理中catch的匹配过程: 实现动态类型转换dynamic_cast. 1. typeid操作符的实现 1.1. ...

  3. 【转载】C/C++杂记:运行时类型识别(RTTI)与动态类型转换原理

    原文:C/C++杂记:运行时类型识别(RTTI)与动态类型转换原理 运行时类型识别(RTTI)的引入有三个作用: 配合typeid操作符的实现: 实现异常处理中catch的匹配过程: 实现动态类型转换 ...

  4. C++杂记:运行时类型识别(RTTI)与动态类型转换原理

    运行时类型识别(RTTI)的引入有三个作用: 配合typeid操作符的实现: 实现异常处理中catch的匹配过程: 实现动态类型转换dynamic_cast. 1. typeid操作符的实现 1.1. ...

  5. 利用神器BTrace 追踪线上 Spring Boot应用运行时信息

    概述 生产环境中的服务可能会出现各种问题,但总不能让服务下线来专门排查错误,这时候最好有一些手段来获取程序运行时信息,比如 接口方法参数/返回值.外部调用情况 以及 函数执行时间等信息以便定位问题.传 ...

  6. [SQL Server]无法创建 SSIS 运行时对象,请验证 DTS.dll 是否可用及是否已注册

    很大可能是SQL Server Management Studio(SSMS)版本与当前操作系统不兼容造成的,与数据库本身没有关系,这种情况基本无解,不过可以使用其他机器连本机数据库导入导出数据. 今 ...

  7. Xwork概况 XWork是一个标准的Command模式实现,并且完全从web层脱离出来。Xwork提供了很多核心功能:前端拦截机(interceptor),运行时表单属性验证,类型转换,强大的表达式语言(OGNL – the Object Graph NavigationLanguage),IoC(Inversion of Control反转控制)容器等。 ----------------

    Xwork概况 XWork是一个标准的Command模式实现,并且完全从web层脱离出来.Xwork提供了很多核心功能:前端拦截机(interceptor),运行时表单属性验证,类型转换,强大的表达式 ...

  8. iOS crash log 解析 symbol address = stack address - slide 运行时获取slide的api 利用dwarfdump从dsym文件中得到symbol

    概述: 为什么 crash log 内 Exception Backtrace 部分的地址(stack address)不能从 dsym 文件中查出对应的代码? 因为 ASLR(Address spa ...

  9. 无法定位 Local Database Runtime 安装。请验证 SQL Server Express 是否正确安装以及本地数据库运行时功能是否已启用。

    错误描述: 在与 SQL Server 建立连接时出现与网络相关的或特定于实例的错误.未找到或无法访问服务器.请验证实例名称是否正确并且 SQL Server 已配置为允许远程连接. (provide ...

随机推荐

  1. [EffectiveC++]item38:通过复合塑膜出has -a 或“根据某物实现出”

    Model "has-a"or “is-implemented-in-terms-of” through composition

  2. Linux的man手册共有以下几个章节

    Linux提供了丰富的帮助手册,当你需要查看某个命令的参数时不必到处上网查找,只要man一下即可. Linux的man手册共有以下几个章节: 1.Standard commands (标准命令) 2. ...

  3. servlet-api-2.5.jar - jar not loaded

    由于包重复,把发布后的项目中的servlet-api-2.5.jar删除,不要clean项目,直接重新启动server即可.由于优先使用项目中的包,而实际使用需要tomcat中的包导致,直入页面会报o ...

  4. 【[POI2015]WIL-Wilcze doły】

    第一篇题解确实会被讨论区里的数据hack掉,那么就随便水一个不会被hack掉的题解吧 首先我们尝试着发现这道题的一些结论,你就会发现答案是单调的不降的 这里的答案不降指的是选择每一个位置\(i\)作为 ...

  5. jQuery中append()、prepend()与after()、before()的区别

    转载 未曾见海  https://www.cnblogs.com/afei-qwerty/p/6682963.html 在jQuery中,添加元素有append(),prepend() 和 after ...

  6. mac终端terminal快捷键

    mac终端terminal快捷键: Command + K 清屏 Command + T 新建标签 Command +W  关闭当前标签页 Command + S  保存终端输出 Command + ...

  7. [转] 各种Json解析工具比较 - json-lib/Jackson/Gson/FastJson

    JSON技术的调研报告 一 .各个JSON技术的简介和优劣1.json-libjson-lib最开始的也是应用最广泛的json解析工具,json-lib 不好的地方确实是依赖于很多第三方包,包括com ...

  8. HDU 1789 Doing Homework again(非常经典的贪心)

    Doing Homework again Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Oth ...

  9. WPF引用ActiveX提示没有注册类或不是有效的Win32程序

    VS2017开发WPF时,需要引用UKey组件读取插入的Ukey编号和密钥 该组件在网页端调用时使用ObjectId进行ActiveX注册即可,后来做成WPF客户端进行读取遇到该问题. 解决: 右键项 ...

  10. php导出word格式数据的代码(转)

    本节内容:一个php导出文档的类 例子:<?php /*** 生成word文档的类* by www.jbxue.com*/class word{     function start()    ...