惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Apple Machine Learning Research
Apple Machine Learning Research
博客园_首页
G
Google Developers Blog
aimingoo的专栏
aimingoo的专栏
罗磊的独立博客
博客园 - 【当耐特】
M
MIT News - Artificial intelligence
D
Docker
博客园 - 三生石上(FineUI控件)
博客园 - 司徒正美
人人都是产品经理
人人都是产品经理
博客园 - 叶小钗
月光博客
月光博客
S
SegmentFault 最新的问题
Jina AI
Jina AI
Blog — PlanetScale
Blog — PlanetScale
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
博客园 - Franky
L
LangChain Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Microsoft Azure Blog
Microsoft Azure Blog
阮一峰的网络日志
阮一峰的网络日志
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Last Week in AI
Last Week in AI

博客园 - 谢绝围观

LeetCode 910. Smallest Range II EAC 抓取CD为AAC文件 Binary Indexed Tree (Fenwick Tree) Lint Code 1365. Minimum Cycle Section LintCode 896. Prime Product 简明题解 UVa 1471 - Defense Lines Windows下安装配置MinGW GCC调试环境 详解LeetCode 137. Single Number II LeetCode 309. Best Time to Buy and Sell Stock with Cooldown LeetCode 84. Largest Rectangle in Histogram 修改注册表删除Windows资源管理器 “通过QQ发送” 右键菜单项 LeetCode 312. Burst Balloons LeetCode 287. Find the Duplicate Number LeetCode 10. Regular Expression Matching LeetCode 117. Populating Next Right Pointers in Each Node II 在Windows Azure VM下搭建SSTP VPN - 谢绝围观 Log4net 配置实例 解决Windows Server 2012 下利用RRAS创建VPN断线的问题 - 谢绝围观 慎用静态类static class
利用.NET Code Contracts实现运行时验证
谢绝围观 · 2015-04-09 · via 博客园 - 谢绝围观

.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