《C#高级编程》读书笔记(十四):代码协定
2016-07-28 16:54
399 查看
一,代码协定
代码协定通常称作契约式编程,包括如下三个部分:
前置条件(precondiction):为了调用函数,必须为真的条件,在其违反时,函数决不调用,传递好数据是调用者的责任。
后置条件(postcondion):函数保证能做到的事情,函数完成时的状态,函数有这一事实表示它会结束,不会无休止的循环
类不变项(class invariant):从调用者的角度来看,该条件总是为真,在函数的内部处理过程中,不变项可以为变,但在函数结束后,控制返回调用者时,不变项必须为真。
二,安装插件
要使用代码协定,首先需要安装Code Contracts for .NET插件。
安装插件后,可以在项目的属性页中的Code Contracts标签来配置相关选项:
勾上"Perform Runtime Check"选项,只是可以看到右侧的下拉框有五个选项,这里分别介绍一下它们的区别:
Full表示执行所有的代码协定语句。
Pre and Post表示执行前置和后置条件检查,即Contract.Require和Contract.Ensures。
Preconditions 表示只执行前置条件检查,即Contract.Require。
ReleaseRequires 表示执行public类的public方法的前置条件检查。
None表示不执行代码协定检查,即不进行代码协定注入。
三,前置条件
前置条件检查传递给方法的参数。使用Contract类中的Requires()方法可以定义前置条件。
调用:
因为不满足前置条件,会报出异常:
Require()方法的重载方法:
例如,使用Requires方法的泛型变体可以指定当条件不满足时,调用的异常类型。如果参数o为空,下面的协定就抛出一个ArgumentNullException异常:
为了检测用作参数的集合,Contract类提供了Exists()和ForAll()方法。ForAll()方法检测集合中的没一项,看看他们是否满足条件。
四,后置条件
后置条件定义了方法执行完后共享数据和返回值的保证。尽管后置条件定义了关于返回值的一些保证,但他们必须放在方法的开头;所有的协定要求都必须放在方法的开头。
Ensures()方法的重载方法:
为了保证返回某个值,可以对Ensures()方法的协定使用特定的值Result<T>
还可以比较新旧值。为此应使用OldValue<T>()方法,它返回在方法入口给变量传递的初始值。
五,类不变项
不变量为对象生命周期中的变量定义了协定。Contract.Requires()方法定义了输入要求,Contract.Ensures()方法定义了方法结束时的要求。Contract.Invariant()方法定义了在对象整个生命周期中都必须满足的条件。对Contract.Invariant的调用只能放在应用了ContractInvariantMethod特性的方法内。
部分内容参考了:代码协定(一)——简介
代码协定通常称作契约式编程,包括如下三个部分:
前置条件(precondiction):为了调用函数,必须为真的条件,在其违反时,函数决不调用,传递好数据是调用者的责任。
后置条件(postcondion):函数保证能做到的事情,函数完成时的状态,函数有这一事实表示它会结束,不会无休止的循环
类不变项(class invariant):从调用者的角度来看,该条件总是为真,在函数的内部处理过程中,不变项可以为变,但在函数结束后,控制返回调用者时,不变项必须为真。
二,安装插件
要使用代码协定,首先需要安装Code Contracts for .NET插件。
安装插件后,可以在项目的属性页中的Code Contracts标签来配置相关选项:
勾上"Perform Runtime Check"选项,只是可以看到右侧的下拉框有五个选项,这里分别介绍一下它们的区别:
Full表示执行所有的代码协定语句。
Pre and Post表示执行前置和后置条件检查,即Contract.Require和Contract.Ensures。
Preconditions 表示只执行前置条件检查,即Contract.Require。
ReleaseRequires 表示执行public类的public方法的前置条件检查。
None表示不执行代码协定检查,即不进行代码协定注入。
三,前置条件
前置条件检查传递给方法的参数。使用Contract类中的Requires()方法可以定义前置条件。
public static void MinMax(int min, int max) { Contract.Requires(max>min); //... }
调用:
MinMax(1,1);
因为不满足前置条件,会报出异常:
Require()方法的重载方法:
public static void Requires(bool condition); public static void Requires(bool condition, string userMessage); public static void Requires<TException>(bool condition) where TException : Exception; public static void Requires<TException>(bool condition, string userMessage) where TException : Exception;
例如,使用Requires方法的泛型变体可以指定当条件不满足时,调用的异常类型。如果参数o为空,下面的协定就抛出一个ArgumentNullException异常:
public static void Preconditions(object o) { Contract.Requires<ArgumentNullException>(o!=null,"Preconditions,o may not be null"); }
为了检测用作参数的集合,Contract类提供了Exists()和ForAll()方法。ForAll()方法检测集合中的没一项,看看他们是否满足条件。
public static void ArrayTest(int[] data) { Contract.Requires(Contract.ForAll(data,i=>i<12)); }
四,后置条件
后置条件定义了方法执行完后共享数据和返回值的保证。尽管后置条件定义了关于返回值的一些保证,但他们必须放在方法的开头;所有的协定要求都必须放在方法的开头。
static void PostCondition() { Contract.Ensures(sharedState<6); sharedState = 9; Console.WriteLine($"change sharedState invariant {sharedState}"); sharedState = 3; Console.WriteLine($"before returing change it to a valid value {sharedState}"); }
Ensures()方法的重载方法:
public static void Ensures(bool condition); public static void Ensures(bool condition, string userMessage);
为了保证返回某个值,可以对Ensures()方法的协定使用特定的值Result<T>
static int ReturnValue() { Contract.Ensures(Contract.Result<int>()<6); return 3; }
还可以比较新旧值。为此应使用OldValue<T>()方法,它返回在方法入口给变量传递的初始值。
static int ReturnLargerThanInput(int x) { Contract.Ensures(Contract.Result<int>()>Contract.OldValue<int>(x)); return x + 3; }
五,类不变项
不变量为对象生命周期中的变量定义了协定。Contract.Requires()方法定义了输入要求,Contract.Ensures()方法定义了方法结束时的要求。Contract.Invariant()方法定义了在对象整个生命周期中都必须满足的条件。对Contract.Invariant的调用只能放在应用了ContractInvariantMethod特性的方法内。
private int x = 5; [ContractInvariantMethod] public void ObjectInvariant() { Contract.Invariant(x>5); }
部分内容参考了:代码协定(一)——简介
相关文章推荐
- C#中的try catch finally用法分析
- 【C#新手的白痴疑难】2016.7.28
- excel to datatable (c#用NPOI将excel文件内容读取到datatable数据表中)
- ref和out的原理及区别
- C#设置textBox只能输入数字(正数,负数,小数)简单实现
- C# Crc16 源代码
- C# byte[]、struct、intptr等的相互转换
- C# 关键字
- C#实现字符串倒叙方法整理
- C# 根据IP获取省市
- C#重写和覆写区别
- 【C#基础】(int),int.Parse,Convert.ToInt32三种转换的区别
- C#也能动态生成Word文档并填充数据
- LINQ数据查询 Resharper插件使用
- C#常用的命名规则汇总
- C# 实现打开和关闭可执行文件
- List和数组转换
- 《C#高级编程》读书笔记(十三):应用程序域
- C#环形缓冲区(队列)完全实现
- C# 控制台捕获关闭事件的代码