C# Contract诊断
命名空间 : using System.Diagnostics.Contracts;
属性标记 : [ContractOption(category: "runtime", setting: "checking", enabled: true)]
事件订阅 : Contract.ContractFailed += (sender, e) => { Console.WriteLine(e.Message); };
1、 Requires() 定义前提条件
1 static void MinMax(int min,int max) 2 { 3 Contract.Requires(min <= max); 4 Contract.Requires <ArgumentException>(min <= max); 5 } 6 static void Preconditions(object o) 7 { 8 Contract.Requires<ArgumentNullException>(o != null, "Preconditions, o may not be null"); 9 Console.WriteLine(o.GetType().Name); 10 } 11 static void ArrayTest(int [] data) 12 { 13 Contract.Requires(Contract.ForAll(data, i => i < 12)); 14 Console.WriteLine("ArrayTest contract succeeded"); 15 } 16 public void ArrayTestWithPureMethod(int [] data) 17 { 18 Contract.Requires(Contract.ForAll(data, MyDataCheck)); 19 Console.WriteLine("ArrayWithPureMethod succeeded"); 20 } 21 22 public int MaxVal { get; set; } 23 public bool MyDataCheck(int x) 24 { 25 return x <= MaxVal; 26 }
2、 Ensures() 定义后置条件
1 private static int sharedState = 5; 2 3 static void Postcondition() 4 { 5 Contract.Ensures(sharedState < 6); 6 sharedState = 9; 7 Console.WriteLine("change sharedState invariant {0}", sharedState); 8 sharedState = 3; 9 Console.WriteLine("before returning change it to a valid value {0}", sharedState); 10 } 11 12 static int ReturnValue() 13 { 14 Contract.Ensures(Contract.Result<int>() < 6); 15 return 3; 16 } 17 static int ReturnLargerThanInput(int x) 18 { 19 Contract.Ensures(Contract.Result<int>() > Contract.OldValue<int>(x)); 20 return x+3; 21 } 22 static void OutParameters(out int x, out int y) 23 { 24 Contract.Ensures(Contract.ValueAtReturn<int>(out x) > 5 && Contract.ValueAtReturn<int>(out x) < 20); 25 Contract.Ensures(Contract.ValueAtReturn<int>(out y) % 5 == 0); 26 x = 8; 27 y = 10; 28 }
3、 Invariant() 定义在对象的整个生命周期中都必须满足的条件
1 private int x = 10; 2 [ContractInvariantMethod] 3 private void ObjectInvariant() 4 { 5 Contract.Invariant(x > 5); 6 } 7 8 public void Invariant() 9 { 10 x = 3; 11 Console.WriteLine("invariant value: {0}", x); 12 }
4、 Pure特性,可以把方法和类型标记为纯粹的方法,纯粹指的是自定义方法不会修改对象的任何可见状态。
5、 接口协定
1 [ContractClass(typeof(PersonContract))] 2 public interface IPerson 3 { 4 string FirstName{get;set;} 5 string LastName { get; set; } 6 int Age { get; set; } 7 void ChangeName(string firstName, string lastName); 8 } 9 10 [ContractClassFor(typeof(IPerson))] 11 public abstract class PersonContract:IPerson 12 { 13 string IPerson.FirstName 14 { 15 get 16 { 17 return Contract.Result<string>(); 18 } 19 set 20 { 21 Contract.Requires(value != null); 22 } 23 } 24 25 string IPerson.LastName 26 { 27 get 28 { 29 return Contract.Result<string>(); 30 } 31 set 32 { 33 Contract.Requires(value != null); 34 } 35 } 36 37 int IPerson.Age 38 { 39 get 40 { 41 Contract.Ensures(Contract.Result<int>() >= 0 && Contract.Result<int>() < 121); 42 return Contract.Result<int>(); 43 } 44 set 45 { 46 Contract.Requires(value >= 0 && value < 121); 47 } 48 } 49 50 void IPerson.ChangeName(string firstName, string lastName) 51 { 52 Contract.Requires(firstName != null); 53 Contract.Requires(lastName != null); 54 } 55 } 56 57 58 public class Person:IPerson 59 { 60 public Person() { } 61 public Person(string firstName,string lastName) 62 { 63 this.FirstName = firstName; 64 this.LastName = lastName; 65 } 66 public string FirstName 67 { 68 get ; 69 set; 70 71 } 72 73 public string LastName 74 { 75 get; 76 set; 77 } 78 79 public int Age 80 { 81 get; 82 set; 83 } 84 85 public void ChangeName(string firstName, string lastName) 86 { 87 this.FirstName = firstName; 88 this.LastName = lastName; 89 } 90 }
鹰击长空,鱼翔浅底