一. 摘要

  首先聖殿騎士很高興”WPF 基礎到企業應用系列

能得到大家的關注、支援和認可。看到很多朋友留言希望加快速度的問題,我會盡力的,對你們的熱情關注也表示由衷的感謝。這段時間更新慢的主要原因是因為忙
著用TDD還原MONO的框架,同時也因為一直在研究雲端計算,所以就拖拖拉拉一直沒有釋出後面的文章。由於WPF整個系列是自己的一些粗淺心得和微薄經
驗,所以不會像寫書那麼面面俱到,如果有不足或者錯誤之處也請大家見諒。在今年之內聖殿騎士會盡量完成”WPF 基礎到企業應用系列”和”雲端計算之旅系列“,誠然,由於本人才識淺薄,所以熱切希望和大家共勉!

  由於依賴屬性是WPF和Silverlight的核心概念,微軟在CS和BS平臺上主要精力都放到了WPF和Silverlight技術
上,同時Silverlight也是Windows
Phone的兩大程式設計模型之一(另外一種是XNA),所以我們花費了大量的時間和篇幅進行論述。在上一篇WPF基礎到企業應用系列7——深入剖析依賴屬性中,
我們首先從依賴屬性基本介紹講起,然後過渡到依賴屬性的優先順序、附加屬性、只讀依賴屬性、依賴屬性後設資料、依賴屬性回撥、驗證及強制值、依賴屬性監聽、代
碼段(自動生成)
等相關知識,最後我們模擬一個WPF依賴屬性的實現,由於上篇是根據微軟WPF的BCL原始碼剖析的,所以這篇我們就研究一下.NET的跨平臺版本
MONO,看下它是怎麼來實現這個依賴屬性機制。

二. 本文提綱

· 1.摘要
· 2.本文提綱
· 3.兵馬未動、廢話先行
· 4.依賴屬性續前緣
· 5.引入測試驅動開發
· 6.DependencyProperty測試程式碼
· 7.DependencyProperty實現程式碼
· 8.DependencyObject測試程式碼
· 9.DependencyObject實現程式碼
· 10.PropertyMetadata測試程式碼
· 11.PropertyMetadata實現程式碼
· 12.其他協助類測試程式碼
· 13.其他協助類的實現程式碼
· 14.迴歸並統計覆蓋率
· 15.簡單驗證依賴屬性系統
· 16.本文總結
· 17.相關程式碼下載
· 18.系列進度

三. 兵馬未動,廢話先行

在講這篇文章之前,我們先來拉一拉家常,說點題外話,就當進入正餐之前的一些甜點,當然這裡主要針對.NET平臺而言:

1,淺談軟體技術的發展趨勢及定位

  網際網路的普及應用催生了很多技術的發展與更新,如果仔細深究,你會發現軟體技術的發展趨勢將主要體現在以下四個方面:客戶端軟體開發(其中包括
客戶端軟體、遊戲、中介軟體和嵌入式開發等)、Web
開發(包括傳統的Web技術、Web遊戲以及一些線上應用)、移動裝置軟體開發(主要涉及到手機等移動裝置)、雲端計算開發(公有云、私有云、混合雲會逐漸
界限清晰,雲廠商以及雲平臺也會逐漸整合和成熟起來)。就微軟來說,這四個方面主要如下:

客戶端軟體開發

  目前微軟主要有Win32 應用程式、MFC 應用程式、WinForm應用程式和WPF
應用程式作為開發選擇,目前這四種技術還會共存,因為不同的需求以及不同的人群都有不同的需要。當然WPF藉助於其強大的功能和迅猛的發展速度很快會成為
首選,這個是值得肯定的。

Web 開發

  在WEB方面微軟主要有ASP.NET、ASP.NET
MVC、Silverlight三種技術,ASP.NET技術已經發展了多年,在未來的很長一段時間內還會是主流,同時結合Silverlight作為局
部和整體應用效果都還很不錯,所以這也是很多企業的首選。ASP.NET
MVC在目前來說應用還不是特別廣泛,不過用過之後感覺也還不錯,只是還需要一段時間的適應過程而已。Silverlight在構建區域性應用和整站應用都
發揮了不錯的優勢,在Windows Phone中也表現得不錯,所以這個技術將會一直熱下去。

移動裝置軟體開發

  移動裝置方面可謂是現在眾廠商競爭最激烈的市場之一,也是傳統技術和新型技術的主要戰場之一。微軟現在主推的Windows
Phone開發主要包括Silverlight和XNA兩種技術,Windows
Phone開發逐漸變得和ASP.NET開發一樣簡單,這也是微軟的一個目標。

雲端計算開發

  雲端計算現在基本上成了網際網路的第一大熱門詞,不管是軟體為主導的企業,還是以硬體為主導的企業,都捲入了這場紛爭與革命。微軟的雲平臺——
Windows Azure Platform,它是微軟完整的雲端計算平臺,目前包含了如下三大部分(Windows
Azure:執行在雲中的作業系統,對於使用者來說是虛擬且透明的,其中提供了Compute(計算),Storage(儲存),以及Manage(管理)
這三個主要功能及其底層服務,使用起來相當的便捷。SQL Azure:執行於雲中的一個關聯式資料庫,和SQL Server
2008類似,但是在功能上還沒有那麼強大。AppFabric:全名是Windows Azure platform
AppFabric,提供了訪問控制、服務匯流排等服務,主要用於把基礎應用連線到雲中)。
其實把這四個方面總結起來就是傳說中的微軟“三屏一雲”戰略,從中也可以看出微軟逍遙於天地,縱橫於宇內,嘯傲於世間,雄霸於大地的梟雄戰略!

2,淺談微軟跨平臺與MONO

  在談之前我們先看一下什麼是MONO?MONO專案是由Ximian發起、Miguel de
lcaza領導、Novell公司主持的專案。它是一個致力於開創.NET在Linux,FreeBSD,Unix,Mac OS
X和Solaris等其他平臺使用的開源工程。它包含了一個C#語言的編譯器,一個CLR的執行時,和一組類庫,並逐漸實現了
ADO.NET、ASP.NET、WinForm、Silverlight(可惜沒有實現強大的WPF),能夠使得開發人員在其他平臺用C#開發程式。

值得看好的地方:

1,跨平臺:開創.NET在Linux,FreeBSD,Unix,Mac OS X和Solaris等其他平臺使用,這是微軟沒有實現的,但是MONO進行了補充,所以值得看好。
2,開源:不論使用什麼技術,大家似乎都希望能夠用開源的產品,一方面是考慮到技術的可控性和可維護性;另一方面則是考慮到安全性,當然在另一個角度也是可以學習到其中的一些技術和思想,所以大家對開源總是報以歡迎的態度。
3,不同的方式實現.NET框架:由於微軟對技術申請了專利,所以MONO不能盲目的模仿,對很多細節都改用自己的方式進行了實現,所以我們也可以學到很多不一樣的實現方式。
4,持續更新:MONO從一開始到現在始終在更新,其中包括bug修復、版本升級、增加新的功能及應用,所以相信它會在不斷的更新中更加完善。

不足之處:

1.模仿但要避免專利:由於是模仿微軟.NET平臺,但因為微軟對程式碼申請了專利,所以MONO只能採用其它實現方式來實現同樣的功能,這樣一來很多地方就會實現得很累贅,效率也會受損。
2.沒有擺脫實驗產品的頭銜:由於它目前的使用比較低,所以資訊反饋和持續改進就做得比較弱,這也是目前功能完善得比較慢的原因之一吧。
3,功能還需要完善:一些主要功能還未實現,如作為Windows平臺最基礎的COM和COM+功能沒有儲存,像MSMQ等訊息佇列,訊息傳送的功
能也沒有實現,對ADO.NET、XML等核心功能效率有待提升,對BCL庫程式碼也有很多需要優化的地方,強大的WPF也沒有引入。
4.效率和使用者體驗還有待提升。

與微軟之間的關係

微軟與MONO之間的關係也一直處於不冷不熱的狀態,沒有明確的反對,也沒有明確的支援,究其原因筆者認為主要有以下兩點:
1,微軟帶來最大收益的產品仍舊是Windows作業系統和Office等軟體,微軟在其他領域盈利都沒有這兩大產品來得直接。而.NET作為微軟
的強大開發平臺,是不希望落在其他平臺上執行的,這樣就會削弱Windows作業系統和Office等軟體的市場佔有率,所以讓.NET跨平臺對微軟來說
是一件捨本求末的事情,這也是微軟不主張.NET執行於其他平臺的主要原因,你想微軟是一個以技術為主導的公司,任何IT市場都會有它的身影,如果想
讓.NET跨平臺,那豈不是一件很輕而易舉的事情嗎?
2,由於MONO還沒有成熟,在很多方面都表現得像一個實驗室產品,在根本上沒有對微軟構成威脅,況且在外界質疑.NET是否能跨平臺的時候,還有一個現身的說法,所以微軟也不會明確的反對和支援。

總結

  雖然目前來說MONO喜憂參半,但優點始終要大於缺點,畢竟每一個框架或者產品都是慢慢不斷改進而完善的,更何況開源必將是未來的一個趨勢,所以我們有理由也有信心期待它接下來的發展。

3,談談原始碼研究與TDD

  大家都有一個共識:如果你想研究某個框架或者工具的原始碼,那先必須熟練使用它,熟練之後自然就有一種研究它的衝動,但是往往這個框架或工具比較
龐大,很不容易下手,一個很不錯的方法就是使用TDD。我們都知道TDD的基本思想就是在開發功能程式碼之前,先編寫測試程式碼。也就是說在明確要開發某個功
能後,首先思考如何對這個功能進行測試,並完成測試程式碼的編寫,然後編寫相關的程式碼滿足這些測試用例。然後迴圈進行新增其他功能,直到完全部功能的開發,
在此過程中我們可以藉助一些工具來協助。比如我們現在要研究Nhibernate,那麼我們首先要熟練它的一些功能,然後從一個點出發慢慢編寫單元測試,
然後逐漸完善程式碼,最後直至完成框架的搭建,這樣會給我們帶來莫大的驅動力和成就感。除了微軟的BCL(Base Class
Library)和企業庫以外,大家還可以用TDD來試試還原以下的任一開原始碼:
MVVM Light Toolkit(http://mvvmlight.codeplex.com/)、Prism(http://compositewpf.codeplex.com/)、MONO原始碼(www.mono-project.com

四. 依賴屬性續前緣

  大家都知道WPF和Silverlight帶來了很多新的特性,其中一大亮點是引入了一種新的屬性機制——依賴屬性。依賴屬性基本應用在了
WPF的所有需要設定屬性的元素。依賴屬性根據多個提供物件來決定它的值(可以是動畫、父類元素、繫結、樣式和模板等),同時這個值也能及時響應變化。所
以WPF擁有了依賴屬性後,程式碼寫起來就比較得心應手,功能實現上也變得非常容易了。如果沒有依賴屬性,我們將不得不編寫大量的程式碼。依賴屬性在WPF中
用得非常廣泛,具體在以下幾個方面中表現得尤為突出:
UI的強大屬性體系
Property value inheritance(值繼承)
Metadata(強大的後設資料)
屬性變化通知,限制、驗證
Resources(資源)
Data binding(資料繫結)
Styles、Template(樣式、模板和風格)
路由事件、附加事件、附加行為乃至命令
Animations、3D(動畫和3D)
WPF Designer Integration(WPF設計、開發整合)
  在上一篇WPF基礎到企業應用系列7——深入剖析依賴屬性中,我們對依賴屬性做了較詳細的介紹,那麼下面我們就簡單回顧一下,其實依賴屬性的實現很簡單,只要做以下步驟就可以實現:
第一步: 讓所在型別繼承自 DependencyObject基類,在WPF中,我們仔細觀察框架的類圖結構,你會發現幾乎所有的 WPF 控制元件都間接繼承自DependencyObject型別。
第二步:使用 public static 宣告一個 DependencyProperty的變數,該變數才是真正的依賴屬性 ,看原始碼就知道這裡其實用了簡單的單例模式的原理進行了封裝(建構函式私有),只暴露Register方法給外部呼叫。
第三步:在靜態建構函式中完成依賴屬性的後設資料註冊,並獲取物件引用,看程式碼就知道是把剛才宣告的依賴屬性放入到一個類似於容器的地方,沒有講實現原理之前,請容許我先這麼陳述。
第四步:在前面的三步中,我們完成了一個依賴屬性的註冊,那麼我們怎樣才能對這個依賴屬性進行讀寫呢?答案就是提供一個依賴屬性的例項化包裝屬性,通過這個屬性來實現具體的讀寫操作。
根據前面的四步操作,我們就可以寫出下面的程式碼:
   1: public class SampleDPClass : DependencyObject
   2:  {
   3:      //宣告一個靜態只讀的DependencyProperty欄位
   4:      public static readonly DependencyProperty SampleProperty;
   5:  
   6:      static SampleDPClass()
   7:      {
   8:          //註冊我們定義的依賴屬性Sample
   9:          SampleProperty = DependencyProperty.Register("Sample", typeof(string), typeof(SampleDPClass),
  10:              new PropertyMetadata("Knights Warrior!", OnValueChanged));
  11:      }
  12:  
  13:      private static void OnValueChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
  14:      {
  15:          //當值改變時,我們可以在此做一些邏輯處理
  16:      }
  17:  
  18:      //屬性包裝器,通過它來讀取和設定我們剛才註冊的依賴屬性
  19:      public string Sample
  20:      {
  21:          get { return (string)GetValue(SampleProperty); }
  22:          set { SetValue(SampleProperty, value); }
  23:      }
  24:  }
  通過上面的例子可以看出,我們一般.NET屬性是直接對類的一個私有屬性進行封裝,所以讀取值的時候,也就是直接讀取這個欄位;而依賴屬性則是
通過呼叫繼承自DependencyObject的GetValue()和SetValue來進行操作,它實際儲存在
DependencyProperty的一個IDictionary的鍵-值配對字典中,所以一條記錄中的鍵(Key)就是該屬性的HashCode值,
而值(Value)則是我們註冊的DependencyProperty。 回顧了一些基礎知識,那我們下面就開始今天的依賴屬性系統TDD之旅。