擴充Kevin McFarlane的C#版DesignByContract Framework

來源:互聯網
上載者:User
Kevin McFarlane的C#版DesignByContract Framework實現從02年在CodeProject發布至今,幾乎成為C#開發中大多數朋友使用的事實標準。本文結合對該架構的使用經驗,在Kevin的原始版本的基礎上,使用Strategy Pattern對其進行進一步的擴充,對最常用的檢查語義進行封裝簡化。本文改進的源碼以Public Domain協議發布,也就是說,完全沒有任何限制。

如果您願意,不強制,使用該代碼時,請保留該源碼檔案頂部的注釋。

Kevin McFarlane的C#版DesignByContract Framework實現在CodeProject.com的原文地址:http://www.codeproject.com/csharp/designbycontract.asp

下載改進版本的DesignByContract源碼及測試工程源碼(測試工程為VS2005 VSTS測試工程格式):DesignByContract_Enhanced_Version.zip

使用簡介

對於該架構的基本使用介紹,請參見上面Kevin McFarlane寫在CodeProject.com的原文。

下面主要介紹擴充部分的使用方法。

啟用Trace或Debug的Assertion

類似原始版本,預設情況下Check.Require()等方法失敗會拋出PreconditionException等異常,可以在它的工程的Conditional compilation symbols中添加USE_TRACE_ASSERTION或USE_DEBUG_ASSERTION。這兩個symbols分別表示用System.Diagnostics.Trace.Assert()或System.Diagnostics.Debug.Assert()提示檢驗失敗訊息,而不是預設的拋出異常。

當使用這兩個symbols時,可以在使用代碼的啟動初始化代碼(例如Global.asax的Application_Start)中通過類似下面的代碼改變預設的錯誤提示或日誌記錄方式:

System.Diagnostics.Trace.Listeners.Clear();
System.Diagnostics.Trace.Listeners.Add(new TextWriterTraceListener(Console.Out));

注1:對ASP.NET程式,請總是使用USE_DEBUG_ASSERTION。
注2:預設情況下,.NET 2.0程式工程的trace和debug在工程Debug編譯模式下是預設啟用的,Release編譯模式下trace預設被啟用,debug預設並不啟用,不過,可以在工程的屬性中手動修改這兩個設定。

修改錯誤提示訊息文本模版

原始版本中的預設錯誤提示是English的,而且直接hardcode,並且分散在原始碼各個方法中,如果我們想改變錯誤提示類型就不是那麼方便,在本改進版本中,所有的錯誤提示訊息的文本模版我都提出來放到源檔案的Check類定義最開頭的#region Const Literals中,方便大家修改。如果您需要從外部資源檔中讀取這些資訊,您可以將#region Const Literals中的這些變數都改成private static readonly的,並在Check的static建構函式中從外部資源檔讀取。

基於Strategy模式的Check邏輯封裝和使用

在改進版本中最大的改進在於增加了一組Check Strategies。所有的Check Strategy都實現ICheckStrategy介面,並在Check類中定義了靜態成員變數來方便訪問他們的執行個體。

ICheckStrategy的定義如下:

1        public interface ICheckStrategy
2        {
3            bool Pass(object obj);
4            string GetFailingMessage(string objName);
5        }


Pass方法需要實現對obj的檢查邏輯,返回true表示通過檢查,GetFailingMessage方法用於返回錯誤提示訊息。

本改進版本內建實現了如下的Check Strateies:

NotNull - 可用於檢查任意對象是否為null
NotNullOrEmpty - 可用於檢查string,Array或ICollection類型的對象非null且非空,Array和ICollection為空白這裡指其包含的元素個數為0
IsAssignableTo<TargetType> - 可使用者檢查指定對象是否可以被轉換為TargetType類型的執行個體
GreaterThan<T>/LessThan<T>/GreaterThanOrEqual<T>/LessThanOrEqual<T> - 顧名思義,這一組Strategies可用於檢查大於、小於等範圍

這些類並不需要也不能(內建實作類別的建構函式是private的,不能直接調用)顯式執行個體化,只需要使用Check類的靜態成員進行訪問:

如:

Check.NotNull
Check.NotNullOrEmpty
Check.IsAssignableTo<TargetType>()
Check.GreaterThan<T>(T compareValue)
Check.LessThan<T>(T compareValue)
Check.GreaterThanOrEqual<T>(T compareValue)
Check.LessThanOrEqual<T>(T compareValue)

同時,本改進版本也為Check的Require,Ensure等方法增加了一個象下面這樣的重載:

public static void Require(object obj, string objName, params ICheckStrategy[] strategies)

該重載的第一個參數為要檢查的對象,第二個參數表述被檢查對象的描述名稱(不一定是變數或參數名,可以使更易於理解的描述名稱),第三個參數是一組可變數量的ICheckStategy執行個體。

使用樣本(更多使用樣本可以參見本文原始碼中的測試工程):

1        private static void RequireStrategy(TestClass obj, object objs, object objList)
2        {
3            Check.Require(obj, "obj", Check.NotNull);
4            Check.Require(objs, "objs", Check.NotNull, Check.IsAssignableTo<Array>(), Check.NotNullOrEmpty);
5            Check.Require(objList, "objList", Check.NotNull, Check.IsAssignableTo<ICollection>(), Check.NotNullOrEmpty);
6        }

範例程式碼中的RequireStategy方法的被檢查參數類型可以但不一定是強型別的。

對於最常用的NotNull檢測,如Check.Require(obj, "obj", Check.NotNull)中,Check.NotNull可以不指定,也就是說Check.Require(obj, "obj")等價於顯式指定Check.NotNull。

Check.Require()的這個重載的最後一組參數是一組Check Stategies,當指定多個時,他們的Pass方法會被依次調用,一旦遇到Pass返回false,則終止後續檢查,提示資訊只包含第一個Pass通不過的Stategy的錯誤提示。

以上範例程式碼中的第二、三個Require()方法的調用,相當於檢查數組或集合對象的類型和是否非空(包含的元素數為0)。NotNullOrEmpty這個Strategy也可以用於對string類型的檢查。對非string、Array或ICollection類型,他的Pass方法總是返回false的。

類似的,使用GreaterThan等Strategies的範例程式碼如下:

1        private static void CompareArguments(int x, int y, double z)
2        {
3            Check.Require(x, "x", Check.GreaterThan<int>(0));
4            Check.Require(y, "y", Check.LessThanOrEqual<int>(0));
5            Check.Require(z, "z", Check.GreaterThanOrEqual<double>(0.1));
6        }

我們也可以用像Check.Require(x, "x", Check.GreaterThan<int>(0), Check.LessThanOrEqual<int>(10))這樣的語法檢查x是否0<x<=10。

您可能要問使用Strategy這樣的文法相比Check.Require(obj != null, "obj could not be null.")這樣的文法有何優勢?

最大的優勢在於,您不必對常用的檢查類型一遍遍重複的指定錯誤的描述資訊,如"obj could not be null."這種描述資訊,可以少打很多字母。而且,基於Strategy使得,對常用檢查邏輯的封裝擴充非常靈活便捷。我們可以方便的繼承ICheckStrategy介面,擴充我們自己的查詢邏輯。

前面說過了,在Check類的#region Const Literals中定義了所有的預設錯誤描述訊息模版,我們可以根據需要修改預設的提示訊息,當然,對大多數應用來說,使用預設的English提示訊息也足夠了。下面簡單列舉了在預設拋出異常工作模式下一些常見的Strategy檢查失敗後的錯誤訊息:

Check.NotNull - Test method DesignByContract.UnitTests.TestPreconditionNull threw exception:  DesignByContract.PreconditionException: obj could not be null.

Check.NotNullOrEmpty - Test method DesignByContract.UnitTests.TestPreconditionStrategyCollectionEmpty threw exception:  DesignByContract.PreconditionException: objList could not be null or empty.

Check.IsAssignableTo<ICollection>() - Test method DesignByContract.UnitTests.TestPreconditionStrategyCollectionNotIsAssignableFrom threw exception:  DesignByContract.PreconditionException: objList is not assignable to System.Collections.ICollection.

Check.GreaterThanOrEqual<double>(0.1) - Test method DesignByContract.UnitTests.TestCompareDoubleGreaterThanOrEqual threw exception:  DesignByContract.PreconditionException: obj must be >= 0.1.

Last Updated: 2007/10/5

//The End

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.