code contract
TRANSCRIPT
CODE CONTRACTLarry Nung
AGENDA
IntroductionDesign By Contract(DbC)
Code Contract
ContractsPreconditions
Postconditions
Object Invariants
Contract.Assert & Contract.Assume
Contract.ForAll & Contract.Exists
Interface & Abstract Method Contracts
Contract Reference Assembly
ReferenceQ & A
INTRODUCTION
Design By Contract(DbC) 要求軟體設計者為軟體組件定義正式的,精
確的並且可驗證的介面。 明確描述雙方的權利與義務。 降低程式的錯誤發生率。 提高程式的品質。
提升自動測試程度
CODE CONTRACT
提升自動測試程度
靜態驗證
CODE CONTRACT
提升自動測試程度
靜態驗證
執行階段驗證
CODE CONTRACT
提升自動測試程度
靜態驗證
執行階段驗證
文件產生
CODE CONTRACT
CODE CONTRACT
可以透過設定啟用 / 關閉 Intellisense 提示強化
CODE CONTRACT
Framewrok 4.0+
Namespace System.Diagnostics.Contracts
Assemble
CODE CONTRACT
CODE CONTRACT
void Test(List<object> array, int index, object value) { Contract.Requires(index >= 0); Contract.Ensures(array.Count == Contract.OldValue(array.Count) + 1); array.Insert(index, value); }
CODE CONTRACTprivate void Test(List<object> array, int index, object value){
List<object> Contract.Old(array);
int Contract.Old(Count); __ContractsRuntime.Requires(index >= 0, null, "index >= 0");
try {
Contract.Old(array) = array;
} catch (Exception exception1) {
if (exception1 == null) { throw; }
}
try {
Contract.Old(Count) = array.Count;
} catch (Exception exception2) {
if (exception2 == null) { throw; }
}
array.Insert(index, value);
if (__ContractsRuntime.insideContractEvaluation <= 4) {
try {
__ContractsRuntime.insideContractEvaluation++;
__ContractsRuntime.Ensures(Contract.Old(array).Count == (Contract.Old(Count) + 1), null, "array.Count == Contract.OldValue(array.Count) + 1");
} finally {
__ContractsRuntime.insideContractEvaluation--;
}
}
}
CONTRACTS
PRECONDITIONS
用來驗證進入方法或是屬性時所必須滿足的需求條件
使用 Contract.Requires 方法表示
Contract.Requires(x != null );
Contract.Requires<ArgumentNullException>(x != null, "x is null");
if(x == null) throw new ArguementNullException(); Contract.EndContractBlock();
POSTCONDITIONS
用來驗證方法或屬性中止時所需滿足的需求條件
標準後置條件
Contract.Ensures( this .F > 0 );
例外後置條件
Contract.EnsuresOnThrow<T>( this.F > 0 );
POSTCONDITIONS
特殊後置條件 ( 方法傳回值、前置狀態值、與輸出參數 )
Contract.Ensures(0 < Contract.Result<int>());
void IArray.Insert(int index, Object value){ Contract.Requires(index >= 0); Contract.Requires(index <=
((IArray)this).Count); Contract.Ensures(((IArray)this).Count ==
Contract.OldValue(((IArray)this).Count) + 1); }
POSTCONDITIONS
前置狀態值不得參考方法的傳回值與用傳址方式帶入的參數
Contract.OldValue(Contract.Result<int>() + x) // ERROR
如數量詞範圍相依於方法傳回值,前置狀態值不得相依於數量詞的繫結變數
Contract. ForAll (0,Contract. Result<int>(),i => Contract.OldValue(xs[i]) > 3 ); // ERROR
POSTCONDITIONS
除 ForAll 或 Exists 外,前置狀態值不得出現在匿名委派的主體中
Method( ... (T t) => Contract.OldValue(... t ...) ... ); // ERROR
前置狀態值除非是當方法呼叫的索引子或引數使用,否則不得在 ForAll 或 Exists 呼叫中參考匿名委派的參數
Contract. ForAll (0, xs .Length, i => Contract.OldValue(xs[i]) > 3); // OK
Contract. ForAll (0, xs .Length, i => Contract.OldValue(i) > 3 ); // ERROR
OBJECT INVARIANTS
用來驗證總是需要滿足的不變條件
使用 ContractInvariantMethodAttribute 屬性搭配Contract .Invariant 去做驗證
public int MyProperty { get; set; } …[ContractInvariantMethod] void ObjectInvariant() { Contract.Invariant(MyProperty >= 0); }
OBJECT INVARIANTS
OBJECT INVARIANTSpublic int MyProperty
{
[CompilerGenerated]
get
{
int Contract.Result = this.<MyProperty>k__BackingField;
if (!this.$evaluatingInvariant$)
{
__ContractsRuntime.Ensures(Contract.Result >= 0, null, "MyProperty >= 0");
}
return Contract.Result;
}
[CompilerGenerated]
set
{
if (!this.$evaluatingInvariant$)
{
__ContractsRuntime.Requires(value >= 0, null, "MyProperty >= 0");
}
this.<MyProperty>k__BackingField = value;
if (!this.$evaluatingInvariant$) { }
this.$InvariantMethod$();
}
}
CONTRACT.ASSERT & CONTRACT.ASSUME
Contract.Assert(this.privateField > 0);
Contract.Assert(this.x == 3, "Why isn't the value of x 3?");
CONTRACT.ASSERT & CONTRACT.ASSUME
Contract.Assume(this.privateField > 0);
Contract.Assume(this.x == 3, "Static checker assumed this");
CONTRACT.FORALL & CONTRACT.EXISTS
public int Foo<T>(IEnumerable<T> xs){
Contract.Requires(Contract.ForAll (xs , x => x != null) );
}
public int Foo<T>(T[] xs){
Contract. Requires ( Contract.ForAll (0,xs.Length,index => xs[index] != null));
}
CONTRACT.FORALL & CONTRACT.EXISTS
public int Foo<T>(IEnumerable<T> xs){
Contract.Requires(Contract.Exists(xs , x => x != null) );
}
INTERFACE & ABSTRACT METHOD CONTRACTS
INTERFACE & ABSTRACT METHOD CONTRACTS[ContractClass(typeof(IFooContract))]
interface IFoo {
int Count { get; }
void Put(int value);
}
[ContractClassFor(typeof(IFoo))]
abstract class IFooContract : IFoo {
int IFoo.Count {
get {
Contract.Ensures(0 <= Contract.Result<int>());
return default(int); // dummy return
}
}
void IFoo.Put(int value) {
Contract.Requires(0 <= value);
}
}
INTERFACE & ABSTRACT METHOD CONTRACTS[ContractClass(typeof(FooContract))]
abstract class Foo {
public abstract int Count { get; }
public abstract void Put(int value);
}
[ContractClassFor(typeof(Foo))]
abstract class FooContract : Foo {
public override int Count {
get {
Contract.Ensures(0 <= Contract.Result<int>());
return default(int); // dummy return
}
}
public override void Put(int value) {
Contract.Requires(0 <= value);
}
}
CONTRACT REFERENCE ASSEMBLY
CONTRACT REFERENCE ASSEMBLY
CONTRACT REFERENCE ASSEMBLY
CONTRACT REFERENCE ASSEMBLY
REFERENCE
REFERENCE
Code Contracts (1) - 概念與簡介 https://
msdn.microsoft.com/zh-tw/library/dn606159.aspx Code Contracts (2) - 三大合約
https://msdn.microsoft.com/zh-tw/library/dn606157.aspx
Code Contracts (3) - Contract.Assert & Contract.Assume https://
msdn.microsoft.com/zh-tw/library/dn606156.aspx
REFERENCE
Code Contracts (4) - Contract.ForAll & Contract.Exists https://
msdn.microsoft.com/zh-tw/library/dn606166.aspx Code Contracts (5) - 介面合約與抽象方法合約
https://msdn.microsoft.com/zh-tw/library/dn722305.aspx
Code Contracts (6) - Contract Reference Assembly https://msdn.microsoft.com/zh-tw/library/dn7223
06.aspx
Q&A37
QUESTION & ANSWER
38
THE END