Dot-Net-4.0

程式碼合同 - 假設與要求

  • January 21, 2011

這兩種說法有什麼區別?

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 意味著呼叫此方法的程式碼 必須確保條件成立。
  • 假設意味著這種方法正在做出一個應該始終成立的假設。

引用自:https://stackoverflow.com/questions/4758460