Dot-Net-4.0
程式碼合同 - 假設與要求
這兩種說法有什麼區別?
Contract.Requires(string.IsNullOrWhiteSpace(userName)); Contract.Assume(string.IsNullOrWhiteSpace(userName));
想像一下,你有一個這樣的方法:
bool ContainsAnX(string s) { return s.Contains("X"); }現在,如果你傳遞給它,這個方法總是會失敗
null,所以你要確保這永遠不會發生。這是Contract.Requires為了什麼。它為方法設置了一個先決條件,該條件必須為真才能使方法正確執行。在這種情況下,我們將有:bool ContainsAnX(string s) { Contract.Requires(s != null); return s.Contains("X"); }(注意:
Requires並且Ensures必須始終位於方法的開頭,因為它們是有關整個方法的資訊。Assume用於程式碼本身,因為它是有關程式碼中該點的資訊。)現在,在呼叫“ContainsAnX”方法的程式碼中,您必須確保字元串不為空。您的方法可能如下所示:
void DoSomething() { var example = "hello world"; if (ContainsAnX(example)) Console.WriteLine("The string contains an 'X'."); else Console.WriteLine("The string does not contain an 'X'."); }這將正常工作,並且靜態檢查器可以證明它
example不為空。但是,您可能正在呼叫外部庫,這些庫沒有關於它們返回的值的任何資訊(即它們不使用程式碼協定)。讓我們更改範例:
void DoSomething() { var example = OtherLibrary.FetchString(); if (ContainsAnX(example)) Console.WriteLine("The string contains an 'X'."); else Console.WriteLine("The string does not contain an 'X'."); }如果
OtherLibrary不使用程式碼合同,靜態檢查器將抱怨example可能為空。也許他們的庫文件說該方法永遠不會返回 null (或者永遠不應該!)。在這種情況下,我們比靜態檢查器知道的更多,所以我們可以告訴它**
Assume**變數永遠不會為空:void DoSomething() { var example = OtherLibrary.FetchString(); Contract.Assume(example != null); if (ContainsAnX(example)) Console.WriteLine("The string contains an 'X'."); else Console.WriteLine("The string does not contain an 'X'."); }現在,靜態檢查器就可以了。如果你啟用了執行時契約,Assume 也會在執行時被檢查。
您可能需要 Assume 的另一種情況是,當您的先決條件非常複雜並且靜態檢查器很難證明它們時。在這種情況下,您可以稍微推動一下以幫助它:)
在執行時行為方面,使用 Assume 和 Requires 之間不會有太大區別。但是,靜態檢查器的結果會有很大的不同。每個人的含義也不同,在失敗的情況下誰對錯誤負責:
- Requires 意味著呼叫此方法的程式碼 必須確保條件成立。
- 假設意味著這種方法正在做出一個應該始終成立的假設。