色尼玛亚洲综合影院,亚洲3atv精品一区二区三区,麻豆freexxxx性91精品,欧美在线91

依賴屬性之“風(fēng)云再起”

  一. 摘要

  首先圣殿騎士很高興”WPF 基礎(chǔ)到企業(yè)應(yīng)用系列” 能得到大家的關(guān)注、支持和認(rèn)可。看到很多朋友留言希望加快速度的問題,我會(huì)盡力的,對(duì)你們的熱情關(guān)注也表示由衷的感謝。這段時(shí)間更新慢的主要原因是因?yàn)槊χ肨DD還原MONO的框架,同時(shí)也因?yàn)橐恢痹谘芯吭朴?jì)算,所以就拖拖拉拉一直沒有發(fā)布后面的文章。由于WPF整個(gè)系列是自己的一些粗淺心得和微薄經(jīng)驗(yàn),所以不會(huì)像寫書那么面面俱到,如果有不足或者錯(cuò)誤之處也請(qǐng)大家見諒。在今年之內(nèi)圣殿騎士會(huì)盡量完成”WPF 基礎(chǔ)到企業(yè)應(yīng)用系列”和”云計(jì)算之旅系列“,誠(chéng)然,由于本人才識(shí)淺薄,所以熱切希望和大家共勉!

  由于依賴屬性是WPF和Silverlight的核心概念,微軟在C/S和B/S平臺(tái)上主要精力都放到了WPF和Silverlight技術(shù)上,同時(shí)Silverlight也是Windows Phone的兩大編程模型之一(另外一種是XNA),所以我們花費(fèi)了大量的時(shí)間和篇幅進(jìn)行論述。在上一篇WPF基礎(chǔ)到企業(yè)應(yīng)用系列7——深入剖析依賴屬性中,我們首先從依賴屬性基本介紹講起,然后過(guò)渡到依賴屬性的優(yōu)先級(jí)、附加屬性、只讀依賴屬性、依賴屬性元數(shù)據(jù)、依賴屬性回調(diào)、驗(yàn)證及強(qiáng)制值、依賴屬性監(jiān)聽、代碼段(自動(dòng)生成) 等相關(guān)知識(shí),最后我們模擬一個(gè)WPF依賴屬性的實(shí)現(xiàn),由于上篇是根據(jù)微軟WPF的BCL源碼剖析的,所以這篇我們就研究一下.NET的跨平臺(tái)版本MONO,看下它是怎么來(lái)實(shí)現(xiàn)這個(gè)依賴屬性機(jī)制。

  二. 本文提綱

· 1.摘要

· 2.本文提綱

· 3.兵馬未動(dòng)、廢話先行

· 4.依賴屬性續(xù)前緣

· 5.引入測(cè)試驅(qū)動(dòng)開發(fā)

· 6.DependencyProperty測(cè)試代碼

· 7.DependencyProperty實(shí)現(xiàn)代碼

· 8.DependencyObject測(cè)試代碼

· 9.DependencyObject實(shí)現(xiàn)代碼

· 10.PropertyMetadata測(cè)試代碼

· 11.PropertyMetadata實(shí)現(xiàn)代碼

· 12.其他協(xié)助類測(cè)試代碼

· 13.其他協(xié)助類的實(shí)現(xiàn)代碼

· 14.回歸并統(tǒng)計(jì)覆蓋率

· 15.簡(jiǎn)單驗(yàn)證依賴屬性系統(tǒng)

· 16.本文總結(jié)

· 17.相關(guān)代碼下載

· 18.系列進(jìn)度

  三. 兵馬未動(dòng),廢話先行

  在講這篇文章之前,我們先來(lái)拉一拉家常,說(shuō)點(diǎn)題外話,就當(dāng)進(jìn)入正餐之前的一些甜點(diǎn),當(dāng)然這里主要針對(duì).NET平臺(tái)而言:

  1,淺談軟件技術(shù)的發(fā)展趨勢(shì)及定位

  互聯(lián)網(wǎng)的普及應(yīng)用催生了很多技術(shù)的發(fā)展與更新,如果仔細(xì)深究,你會(huì)發(fā)現(xiàn)軟件技術(shù)的發(fā)展趨勢(shì)將主要體現(xiàn)在以下四個(gè)方面:客戶端軟件開發(fā)(其中包括客戶端軟件、游戲、中間件和嵌入式開發(fā)等)、Web 開發(fā)(包括傳統(tǒng)的Web技術(shù)、Web游戲以及一些在線應(yīng)用)、移動(dòng)設(shè)備軟件開發(fā)(主要涉及到手機(jī)移動(dòng)設(shè)備)、云計(jì)算開發(fā)(公有云、私有云、混合云會(huì)逐漸界限清晰,云廠商以及云平臺(tái)也會(huì)逐漸整合和成熟起來(lái))。就微軟來(lái)說(shuō),這四個(gè)方面主要如下:

客戶端軟件開發(fā)

  目前微軟主要有Win32 應(yīng)用程序、MFC 應(yīng)用程序、WinForm應(yīng)用程序和WPF 應(yīng)用程序作為開發(fā)選擇,目前這四種技術(shù)還會(huì)共存,因?yàn)椴煌男枨笠约安煌娜巳憾加胁煌男枰.?dāng)然WPF借助于其強(qiáng)大的功能和迅猛的發(fā)展速度很快會(huì)成為首選,這個(gè)是值得肯定的。

Web 開發(fā)

  在WEB方面微軟主要有ASP.NETASP.NET MVC、Silverlight三種技術(shù),ASP.NET技術(shù)已經(jīng)發(fā)展了多年,在未來(lái)的很長(zhǎng)一段時(shí)間內(nèi)還會(huì)是主流,同時(shí)結(jié)合Silverlight作為局部和整體應(yīng)用效果都還很不錯(cuò),所以這也是很多企業(yè)的首選。ASP.NET MVC在目前來(lái)說(shuō)應(yīng)用還不是特別廣泛,不過(guò)用過(guò)之后感覺也還不錯(cuò),只是還需要一段時(shí)間的適應(yīng)過(guò)程而已。Silverlight在構(gòu)建局部應(yīng)用和整站應(yīng)用都發(fā)揮了不錯(cuò)的優(yōu)勢(shì),在Windows Phone中也表現(xiàn)得不錯(cuò),所以這個(gè)技術(shù)將會(huì)一直熱下去。

移動(dòng)設(shè)備軟件開發(fā)

  移動(dòng)設(shè)備方面可謂是現(xiàn)在眾廠商競(jìng)爭(zhēng)最激烈的市場(chǎng)之一,也是傳統(tǒng)技術(shù)和新型技術(shù)的主要戰(zhàn)場(chǎng)之一。微軟現(xiàn)在主推的Windows Phone開發(fā)主要包括Silverlight和XNA兩種技術(shù),Windows Phone開發(fā)逐漸變得和ASP.NET開發(fā)一樣簡(jiǎn)單,這也是微軟的一個(gè)目標(biāo)。

云計(jì)算開發(fā)

  云計(jì)算現(xiàn)在基本上成了互聯(lián)網(wǎng)的第一大熱門詞,不管是軟件為主導(dǎo)的企業(yè),還是以硬件為主導(dǎo)的企業(yè),都卷入了這場(chǎng)紛爭(zhēng)與革命。微軟的云平臺(tái)——Windows Azure Platform,它是微軟完整的云計(jì)算平臺(tái),目前包含了如下三大部分(Windows Azure:運(yùn)行在云中的操作系統(tǒng),對(duì)于用戶來(lái)說(shuō)是虛擬且透明的,其中提供了Compute(計(jì)算),Storage(存儲(chǔ)),以及Manage(管理)這三個(gè)主要功能及其底層服務(wù),使用起來(lái)相當(dāng)?shù)谋憬荨QL Azure:運(yùn)行于云中的一個(gè)關(guān)系數(shù)據(jù)庫(kù),和SQL Server 2008類似,但是在功能上還沒有那么強(qiáng)大。AppFabric:全名是Windows Azure platform AppFabric,提供了訪問控制、服務(wù)總線等服務(wù),主要用于把基礎(chǔ)應(yīng)用連接到云中)。

  其實(shí)把這四個(gè)方面總結(jié)起來(lái)就是傳說(shuō)中的微軟“三屏一云”戰(zhàn)略,從中也可以看出微軟逍遙于天地,縱橫于宇內(nèi),嘯傲于世間,雄霸于大地的梟雄戰(zhàn)略!

  2,淺談微軟跨平臺(tái)與MONO

  在談之前我們先看一下什么是MONO?MONO項(xiàng)目是由Ximian發(fā)起、Miguel de lcaza領(lǐng)導(dǎo)、Novell公司主持的項(xiàng)目。它是一個(gè)致力于開創(chuàng).NET在Linux,F(xiàn)reeBSD,Unix,Mac OS X和Solaris等其他平臺(tái)使用的開源工程。它包含了一個(gè)C#語(yǔ)言的編譯器,一個(gè)CLR的運(yùn)行時(shí),和一組類庫(kù),并逐漸實(shí)現(xiàn)了 ADO.NETASP.NET、WinForm、Silverlight(可惜沒有實(shí)現(xiàn)強(qiáng)大的WPF),能夠使得開發(fā)人員在其他平臺(tái)用C#開發(fā)程序。

  ◆ 值得看好的地方:

1,跨平臺(tái):開創(chuàng).NET在Linux,F(xiàn)reeBSD,Unix,Mac OS X和Solaris等其他平臺(tái)使用,這是微軟沒有實(shí)現(xiàn)的,但是MONO進(jìn)行了補(bǔ)充,所以值得看好。

2,開源:不論使用什么技術(shù),大家似乎都希望能夠用開源的產(chǎn)品,一方面是考慮到技術(shù)的可控性和可維護(hù)性;另一方面則是考慮到安全性,當(dāng)然在另一個(gè)角度也是可以學(xué)習(xí)到其中的一些技術(shù)和思想,所以大家對(duì)開源總是報(bào)以歡迎的態(tài)度。

3,不同的方式實(shí)現(xiàn).NET框架:由于微軟對(duì)技術(shù)申請(qǐng)了專利,所以MONO不能盲目的模仿,對(duì)很多細(xì)節(jié)都改用自己的方式進(jìn)行了實(shí)現(xiàn),所以我們也可以學(xué)到很多不一樣的實(shí)現(xiàn)方式。

4,持續(xù)更新:MONO從一開始到現(xiàn)在始終在更新,其中包括bug修復(fù)、版本升級(jí)、增加新的功能及應(yīng)用,所以相信它會(huì)在不斷的更新中更加完善。

  ◆ 不足之處:

1.模仿但要避免專利:由于是模仿微軟.NET平臺(tái),但因?yàn)槲④泴?duì)代碼申請(qǐng)了專利,所以MONO只能采用其它實(shí)現(xiàn)方式來(lái)實(shí)現(xiàn)同樣的功能,這樣一來(lái)很多地方就會(huì)實(shí)現(xiàn)得很累贅,效率也會(huì)受損。

2.沒有擺脫實(shí)驗(yàn)產(chǎn)品的頭銜:由于它目前的使用比較低,所以信息反饋和持續(xù)改進(jìn)就做得比較弱,這也是目前功能完善得比較慢的原因之一吧。

3,功能還需要完善:一些主要功能還未實(shí)現(xiàn),如作為Windows平臺(tái)最基礎(chǔ)的COM和COM+功能沒有保存,像MSMQ等消息隊(duì)列,消息傳送的功能也沒有實(shí)現(xiàn),對(duì)ADO.NET、XML等核心功能效率有待提升,對(duì)BCL庫(kù)代碼也有很多需要優(yōu)化的地方,強(qiáng)大的WPF也沒有引入。

4.效率和用戶體驗(yàn)還有待提升。

  ◆ 與微軟之間的關(guān)系

  微軟與MONO之間的關(guān)系也一直處于不冷不熱的狀態(tài),沒有明確的反對(duì),也沒有明確的支持,究其原因筆者認(rèn)為主要有以下兩點(diǎn):

1,微軟帶來(lái)最大收益的產(chǎn)品仍舊是Windows操作系統(tǒng)和Office等軟件,微軟在其他領(lǐng)域盈利都沒有這兩大產(chǎn)品來(lái)得直接。而.NET作為微軟的強(qiáng)大開發(fā)平臺(tái),是不希望落在其他平臺(tái)上運(yùn)行的,這樣就會(huì)削弱Windows操作系統(tǒng)和Office等軟件的市場(chǎng)占有率,所以讓.NET跨平臺(tái)對(duì)微軟來(lái)說(shuō)是一件舍本求末的事情,這也是微軟不主張.NET運(yùn)行于其他平臺(tái)的主要原因,你想微軟是一個(gè)以技術(shù)為主導(dǎo)的公司,任何IT市場(chǎng)都會(huì)有它的身影,如果想讓.NET跨平臺(tái),那豈不是一件很輕而易舉的事情嗎?

2,由于MONO還沒有成熟,在很多方面都表現(xiàn)得像一個(gè)實(shí)驗(yàn)室產(chǎn)品,在根本上沒有對(duì)微軟構(gòu)成威脅,況且在外界質(zhì)疑.NET是否能跨平臺(tái)的時(shí)候,還有一個(gè)現(xiàn)身的說(shuō)法,所以微軟也不會(huì)明確的反對(duì)和支持。

  ◆ 總結(jié)

  雖然目前來(lái)說(shuō)MONO喜憂參半,但優(yōu)點(diǎn)始終要大于缺點(diǎn),畢竟每一個(gè)框架或者產(chǎn)品都是慢慢不斷改進(jìn)而完善的,更何況開源必將是未來(lái)的一個(gè)趨勢(shì),所以我們有理由也有信心期待它接下來(lái)的發(fā)展。

  3,談?wù)勗创a研究與TDD

  大家都有一個(gè)共識(shí):如果你想研究某個(gè)框架或者工具的源碼,那先必須熟練使用它,熟練之后自然就有一種研究它的沖動(dòng),但是往往這個(gè)框架或工具比較龐大,很不容易下手,一個(gè)很不錯(cuò)的方法就是使用TDD。我們都知道TDD的基本思想就是在開發(fā)功能代碼之前,先編寫測(cè)試代碼。也就是說(shuō)在明確要開發(fā)某個(gè)功能后,首先思考如何對(duì)這個(gè)功能進(jìn)行測(cè)試,并完成測(cè)試代碼的編寫,然后編寫相關(guān)的代碼滿足這些測(cè)試用例。然后循環(huán)進(jìn)行添加其他功能,直到完全部功能的開發(fā),在此過(guò)程中我們可以借助一些工具來(lái)協(xié)助。比如我們現(xiàn)在要研究Nhibernate,那么我們首先要熟練它的一些功能,然后從一個(gè)點(diǎn)出發(fā)慢慢編寫單元測(cè)試,然后逐漸完善代碼,最后直至完成框架的搭建,這樣會(huì)給我們帶來(lái)莫大的驅(qū)動(dòng)力和成就感。除了微軟的BCL(Base Class Library)和企業(yè)庫(kù)以外,大家還可以用TDD來(lái)試試還原以下的任一開源代碼:

Spring.NEThttp://www.springframework.NET/)、Castle(http://www.castleproject.org)、log4NEThttp://logging.apache.org/log4NET/)、

NHibernate(http://www.hibernate.org/343.html)、iBATIS.NEThttp://ibatis.apache.org)、Caliburn(http://caliburn.codeplex.com/)、

MVVM Light Toolkit(http://mvvmlight.codeplex.com/)、Prism(http://compositewpf.codeplex.com/)、MONO源碼(www.mono-project.com

  四. 依賴屬性續(xù)前緣

  大家都知道WPF和Silverlight帶來(lái)了很多新的特性,其中一大亮點(diǎn)是引入了一種新的屬性機(jī)制——依賴屬性。依賴屬性基本應(yīng)用在了WPF的所有需要設(shè)置屬性的元素。依賴屬性根據(jù)多個(gè)提供對(duì)象來(lái)決定它的值(可以是動(dòng)畫、父類元素、綁定、樣式和模板等),同時(shí)這個(gè)值也能及時(shí)響應(yīng)變化。所以WPF擁有了依賴屬性后,代碼寫起來(lái)就比較得心應(yīng)手,功能實(shí)現(xiàn)上也變得非常容易了。如果沒有依賴屬性,我們將不得不編寫大量的代碼。依賴屬性在WPF中用得非常廣泛,具體在以下幾個(gè)方面中表現(xiàn)得尤為突出:

UI的強(qiáng)大屬性體系

Property value inheritance(值繼承)

Metadata(強(qiáng)大的元數(shù)據(jù))

屬性變化通知,限制、驗(yàn)證

Resources(資源)

Data binding(數(shù)據(jù)綁定)

Styles、Template(樣式、模板和風(fēng)格)

路由事件、附加事件、附加行為乃至命令

Animations、3D(動(dòng)畫和3D)

WPF Designer Integration(WPF設(shè)計(jì)、開發(fā)集成)

  在上一篇WPF基礎(chǔ)到企業(yè)應(yīng)用系列7——深入剖析依賴屬性中,我們對(duì)依賴屬性做了較詳細(xì)的介紹,那么下面我們就簡(jiǎn)單回顧一下,其實(shí)依賴屬性的實(shí)現(xiàn)很簡(jiǎn)單,只要做以下步驟就可以實(shí)現(xiàn):

第一步: 讓所在類型繼承自 DependencyObject基類,在WPF中,我們仔細(xì)觀察框架的類圖結(jié)構(gòu),你會(huì)發(fā)現(xiàn)幾乎所有的 WPF 控件都間接繼承自DependencyObject類型。
第二步:使用 public static 聲明一個(gè) DependencyProperty的變量,該變量才是真正的依賴屬性 ,看源碼就知道這里其實(shí)用了簡(jiǎn)單的單例模式的原理進(jìn)行了封裝(構(gòu)造函數(shù)私有),只暴露Register方法給外部調(diào)用。
第三步:在靜態(tài)構(gòu)造函數(shù)中完成依賴屬性的元數(shù)據(jù)注冊(cè),并獲取對(duì)象引用,看代碼就知道是把剛才聲明的依賴屬性放入到一個(gè)類似于容器的地方,沒有講實(shí)現(xiàn)原理之前,請(qǐng)容許我先這么陳述。
第四步:在前面的三步中,我們完成了一個(gè)依賴屬性的注冊(cè),那么我們?cè)鯓硬拍軐?duì)這個(gè)依賴屬性進(jìn)行讀寫呢?答案就是提供一個(gè)依賴屬性的實(shí)例化包裝屬性,通過(guò)這個(gè)屬性來(lái)實(shí)現(xiàn)具體的讀寫操作。

  根據(jù)前面的四步操作,我們就可以寫出下面的代碼:

   1: public class SampleDPClass : DependencyObject
   2:  {
   3:      //聲明一個(gè)靜態(tài)只讀的DependencyProperty字段
   4:      public static readonly DependencyProperty SampleProperty;
   5:  
   6:      static SampleDPClass()
   7:      {
   8:          //注冊(cè)我們定義的依賴屬性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:          //當(dāng)值改變時(shí),我們可以在此做一些邏輯處理
  16:      }
  17:  
  18:      //屬性包裝器,通過(guò)它來(lái)讀取和設(shè)置我們剛才注冊(cè)的依賴屬性
  19:      public string Sample
  20:      {
  21:          get { return (string)GetValue(SampleProperty); }
  22:          set { SetValue(SampleProperty, value); }
  23:      }
  24:  }

 

  五. 引入測(cè)試驅(qū)動(dòng)開發(fā)

  1,引入概念

  由于本篇的依賴屬性體系是基于測(cè)試驅(qū)動(dòng)開發(fā)完成的,所以我們就先來(lái)看一下什么叫測(cè)試驅(qū)動(dòng)開發(fā):測(cè)試驅(qū)動(dòng)開發(fā)的基本思想就是在開發(fā)功能代碼之前,先編寫測(cè)試代碼。也就是說(shuō)在明確要開發(fā)某個(gè)功能后,首先思考如何對(duì)這個(gè)功能進(jìn)行測(cè)試,并完成測(cè)試代碼的編寫,然后編寫相關(guān)的代碼滿足這些測(cè)試用例。然后循環(huán)進(jìn)行添加其他功能,直到完全部功能的開發(fā)。由于過(guò)程很長(zhǎng),在寫的時(shí)候也省略了不少步驟,所以有些地方銜接不是那么的流暢,對(duì)此表示非常的抱歉!

  2,注意事項(xiàng)

  根據(jù)自身做項(xiàng)目使用TDD的一點(diǎn)微薄經(jīng)驗(yàn),總結(jié)了以下幾個(gè)注意事項(xiàng):

◆ 找準(zhǔn)切入點(diǎn):

  不論是開發(fā)一個(gè)新的系統(tǒng)還是復(fù)原系統(tǒng),都必須先找準(zhǔn)一個(gè)或多個(gè)切入點(diǎn),從切入點(diǎn)經(jīng)歷”測(cè)試代碼-功能代碼-測(cè)試-重構(gòu)“來(lái)逐漸完善整個(gè)系統(tǒng),往往這個(gè)切入點(diǎn)就是功能點(diǎn),就是這個(gè)系統(tǒng)具備哪些功能,然后根據(jù)這些功能寫出測(cè)試用例。

◆ 測(cè)試列表:

  大家都知道一個(gè)系統(tǒng)或者一個(gè)框架都是很龐大的,如果要引入測(cè)試驅(qū)動(dòng)開發(fā),首先我們必須要有一個(gè)測(cè)試列表,在任何階段想添加功能需求問題時(shí),把相關(guān)功能點(diǎn)加到測(cè)試列表中,然后繼續(xù)開發(fā)的工作。然后不斷的完成對(duì)應(yīng)的測(cè)試用例、功能代碼、重構(gòu)。這樣可以避免疏漏的同時(shí)也能把控當(dāng)前的進(jìn)度。

◆ 測(cè)試驅(qū)動(dòng):

  這個(gè)比較核心。完成某個(gè)功能,某個(gè)類,首先編寫測(cè)試代碼,考慮其如何使用、如何測(cè)試。然后在對(duì)其進(jìn)行設(shè)計(jì)、編碼。這里也強(qiáng)調(diào)先編寫對(duì)功能代碼的判斷用的斷言語(yǔ)句,然后編寫相應(yīng)的輔助語(yǔ)句。

◆ 良好的代碼設(shè)計(jì)及可測(cè)性:

功能代碼設(shè)計(jì)、開發(fā)時(shí)應(yīng)該具有較強(qiáng)的可測(cè)試性。應(yīng)該盡量保持良好的設(shè)計(jì)原則和代碼規(guī)范,如盡量依賴于接口、盡量高內(nèi)聚、低耦合等等。

◆ 模塊或功能隔離:

  不同代碼的測(cè)試應(yīng)該相互隔離。對(duì)一塊代碼的測(cè)試只考慮此代碼的測(cè)試,不要考慮其實(shí)現(xiàn)細(xì)節(jié),不然就會(huì)陷入一團(tuán)亂麻之中,這個(gè)可以通過(guò)MOCK來(lái)實(shí)現(xiàn),同時(shí)在開始的時(shí)候也要?jiǎng)澐趾眠吔纭?/p>

◆ 適當(dāng)引入MOCK:

  在適當(dāng)情況下引入MOCK來(lái)完成單元測(cè)試,這種情況尤其是在邊際交互比較多的案例當(dāng)中,對(duì)于交互比較多且復(fù)雜的多個(gè)類關(guān)系可以用MOCK暫時(shí)模擬,這是一個(gè)不錯(cuò)的解決方案。

◆ 由小到大、由偏到全、統(tǒng)籌兼顧:

  一個(gè)產(chǎn)品或者一個(gè)項(xiàng)目是比較大的,所以我們這里就需要遵循由小到大、由偏到全、統(tǒng)籌兼顧的原則,分解功能和代碼。把所有的規(guī)模大、復(fù)雜性高的工作,分解成小的任務(wù)來(lái)完成,這樣既方便團(tuán)隊(duì)協(xié)作,同時(shí)也減輕了復(fù)雜度,使整個(gè)開發(fā)一下子變得簡(jiǎn)單了許多。

◆ 保持隨時(shí)重構(gòu)的習(xí)慣

  很多開發(fā)者在經(jīng)過(guò)測(cè)試代碼-功能代碼-測(cè)試通過(guò)以后就當(dāng)完成了任務(wù),其實(shí)你會(huì)發(fā)現(xiàn)隨著其他功能的引入或者使用過(guò)程中發(fā)現(xiàn)了很多重復(fù)、冗余的代碼、再或者先前的代碼結(jié)構(gòu)和設(shè)計(jì)不太合理,這個(gè)時(shí)候就需要隨時(shí)的進(jìn)行重構(gòu)和單元測(cè)試,在一方面可以避免產(chǎn)生風(fēng)險(xiǎn),另一方面可以使系統(tǒng)更加完善。

◆ 隨時(shí)進(jìn)行回歸:

  在”測(cè)試代碼-功能代碼-測(cè)試-重構(gòu)“的循環(huán)中一定要記住多回歸,因?yàn)檫@樣可以保證當(dāng)前的代碼是不是會(huì)影響到前面的功能,其實(shí)只需要看看紅綠燈就行。

查看和統(tǒng)計(jì)代碼覆蓋率

  通過(guò)前面的步驟之后,我們就要看一下實(shí)現(xiàn)的功能是否達(dá)到我們的預(yù)期目標(biāo),除了功能完善之外,還要保證代碼的覆蓋率,因?yàn)樗且粋€(gè)系統(tǒng)穩(wěn)定與否、可維護(hù)性與否的一個(gè)重大標(biāo)志。

  3,工具介入

  以后寫關(guān)于TDD的文章可能比較多,同時(shí)也都會(huì)用到這個(gè)工具,所以我們今天對(duì)它也稍帶介紹一下,正所謂“工欲善其事,必先利其器”。根據(jù)官方文檔解釋:TestDriven.NET是Visual Studio的一個(gè)TDD插件,最近版本是TestDriven.NET-3.0.2749 RTM版。其中一些新特性有:支持MSTest、.NET Reflector 6 Pro、VS 2010、Silverlight 4、NUnit 2.5.3,使用項(xiàng)目所用的.NET框架等。 下載地址:http://www.testdriven.NET/  

這個(gè)工具使用起來(lái)比VS自帶的單元測(cè)試和測(cè)試覆蓋功能好用,所以從2008年開始基本就用它作為一個(gè)必備的工具使用。關(guān)于它具體的功能和怎么使用,我們這里不詳細(xì)介紹,網(wǎng)上也有很多文章,大家可以做一下參考和研究。下圖是安裝后以插件的形式出現(xiàn)在VS中的效果:

2010-9-23 19-42-57

  A,基本介紹

  TestDriven.NET原來(lái)叫做NUnitAddIn,它是個(gè)Visual Studio插件,集成了如下測(cè)試框架:NUnit、MbUnit、 ZaneBug、MSTest、NCover、NCoverExplorer、Reflector、TypeMock、dotTrace和MSBee,它主要面向使用TDD的開發(fā)者,主要特性列舉如下:

單鍵運(yùn)行方法、類、命名空間、項(xiàng)目和解決方案中的單元測(cè)試

能夠快速測(cè)試實(shí)例方法、靜態(tài)方法或?qū)傩?/p>

可以直接跳到.NET Reflector中的任何方法、類型、項(xiàng)目或引用中,這個(gè)功能提供了相當(dāng)大的方便

在調(diào)試過(guò)程中可以查看.NET Reflector中的任何模塊或堆棧信息

支持多種單元測(cè)試框架,包括NUnit、MbUnit、xUnit和MSTest

測(cè)試運(yùn)行在自己的進(jìn)程中以消除其他問題和邊際效應(yīng)

可以輕松對(duì)任何目標(biāo)測(cè)試進(jìn)行調(diào)試或執(zhí)行代碼覆蓋率測(cè)試(比微軟自帶的單元測(cè)試和代碼覆蓋功能要好用多了)

支持所有主流的.NET語(yǔ)言:C#、VB、C++和F#

  B,TestDriven.NET 3.0中的新特性:

TestDriven.NET是基于.NET框架的。再由于VS 2010支持使用多個(gè).NET版本,所以支持各個(gè)VS版本和工具就沒有問題了

完全支持在VS 2008和VS 2010中使用MSTest

完全支持.NET Reflector 6 Pro

支持NUnit 2.5.3

支持和兼容VS 2005、VS 2008、VS 2010幾個(gè)版本

支持Silverlight 4的測(cè)試

  C,兼容性

  TestDriven.NET兼容于如下VS版本:Windows XP、Vista、Windows 7、Windows 2000、Windows 2003和Windows 2008(32和64位)上的Visual Studio 2005、2008和2010。官方已經(jīng)不再對(duì)VS 2003支持。

  D,版本

企業(yè)版:每臺(tái)機(jī)器一個(gè)許可認(rèn)證

專業(yè)版:一般的許可形式

個(gè)人版:面向?qū)W生、開源開發(fā)者和試驗(yàn)用戶的免費(fèi)許可(大家可以下載這個(gè)版本,個(gè)人感覺很好用)

  4,關(guān)于本篇

  本篇文章沒有明確的寫作意圖,只是最近在深入研究MONO源碼時(shí)有感而發(fā),當(dāng)然作者本人也只是起到了一個(gè)研究者或者剖析者的角色。首先實(shí)現(xiàn)最簡(jiǎn)單且基本的DependencyProperty.Register功能,然后再實(shí)現(xiàn)DependencyObject的GetValue和SetValue,接著實(shí)現(xiàn)PropertyMetadata的DefaultValue、PropertyChangedCallback、CoerceValueCallback等功能,然后完善DependencyProperty.Register注冊(cè)時(shí)添加ValidateValueCallback、RegisterAttached、RegisterAttachedReadOnly、RegisterReadOnly、OverrideMetadata、GetMetadata和AddOwner等相關(guān)功能。既然有了這些功能,自然就需要完善PropertyMetadata的IsSealed、Merge和OnApply等相關(guān)底層操作。當(dāng)然在中間還需要DependencyObject的ClearValue、CoerceValue、GetLocalValueEnumerator、ReadLocalValue以及其他的Helper類,這里就不一一進(jìn)行說(shuō)明。對(duì)于邊際交互比較多且關(guān)聯(lián)比較大的操作,采用了Mock進(jìn)行暫時(shí)模擬,在開發(fā)完了以后再進(jìn)行了替換。在開發(fā)過(guò)程中,隨時(shí)進(jìn)行單元測(cè)試和覆蓋率的檢查,這樣可以方便查看哪些功能還有問題以及整體的進(jìn)度和質(zhì)量的監(jiān)控。

  六. DependencyProperty測(cè)試代碼

  在寫DependencyProperty測(cè)試代碼之前,我們先看一下它到底有哪些成員和方法,如下圖:

2010-9-26 23-07-52

  了解了上面DependencyProperty的基本功能,我們首先創(chuàng)建一個(gè)繼承自DependencyObject的類ObjectPoker,由于DependencyObject還沒有被創(chuàng)建,所以我們這里就先創(chuàng)建它,然后在ObjectPoker類里面實(shí)現(xiàn)我們的經(jīng)典語(yǔ)句DependencyProperty.Register,由于Register有很多重載,為了方便TDD,就從最簡(jiǎn)單的開始(三個(gè)參數(shù),不牽涉到元數(shù)據(jù)類),然后再創(chuàng)建一個(gè)ObjectPoker的子類,這是方便后面測(cè)試DependencyProperty的相關(guān)功能。

   1: class ObjectPoker : DependencyObject
   2: {
   3:     //注冊(cè)依賴屬性property1
   4:     public static readonly DependencyProperty TestProp1 = DependencyProperty.Register("property1", typeof(string), typeof(ObjectPoker));
   5: }
   6:  
   7: class SubclassPoker : ObjectPoker
   8: {
   9: }

 

  九. DependencyObject實(shí)現(xiàn)代碼

  通過(guò)前面的測(cè)試用例,DependencyObject類的基本功能已經(jīng)完成,不過(guò)我們要注意幾個(gè)要點(diǎn):
  1,依賴屬性其實(shí)終究要DependencyObject和DependencyProperty成對(duì)才能算得上真正的DependencyProperty。

  2,不管是Register、RegisterAttached、RegisterAttachedReadOnly還是RegisterReadOnly操作,我們都要通過(guò)DependencyObject來(lái)操作DependencyProperty的值,也就是通過(guò)DependencyObject這個(gè)外部接口來(lái)操作,DependencyProperty只負(fù)責(zé)注冊(cè)和內(nèi)部處理,不負(fù)責(zé)外部接口。

  3,在DependencyObject中提供了幾個(gè)操作LocalValue的接口的接口,其中包括ReadLocalValue、GetLocalValueEnumerator、CoerceValue和ClearValue等。

  4,在注冊(cè)注冊(cè)依賴屬性時(shí),實(shí)質(zhì)是關(guān)聯(lián)DependencyObject的propertyDeclarations,它是一個(gè)Dictionary<Type,Dictionary<string,DependencyProperty>>類型,但是在register代碼中并沒有完全關(guān)聯(lián)起來(lái),我也比較納悶,所以這點(diǎn)還希望和大家一起探討,微軟的BCL并沒有這么實(shí)現(xiàn)。

   1: using System.Collections.Generic;
   2: //using System.Windows.Threading;
   3:  
   4: namespace System.Windows 
   5: {
   6:     public class DependencyObject
   7:     {
   8:         //依賴屬性其實(shí)終究要DependencyObject和DependencyProperty成對(duì)才能算得上真正的DependencyProperty
   9:         private static Dictionary<Type,Dictionary<string,DependencyProperty>> propertyDeclarations = new Dictionary<Type,Dictionary<string,DependencyProperty>>();
  10:         //該依賴屬性的鍵值對(duì),鍵為DependencyProperty,值為object
  11:         private Dictionary<DependencyProperty,object> properties = new Dictionary<DependencyProperty,object>();
  12:  
  13:         //是否已密封,沒有實(shí)現(xiàn)DependencyObject層次的IsSealed判斷
  14:         public bool IsSealed {
  15:             get { return false; }
  16:         }
  17:  
  18:         //獲取該DependencyObject的DependencyObjectType
  19:         public DependencyObjectType DependencyObjectType { 
  20:             get { return DependencyObjectType.FromSystemType (GetType()); }
  21:         }
  22:  
  23:         //根據(jù)該依賴屬性名,清除它的值
  24:         public void ClearValue(DependencyProperty dp)
  25:         {
  26:             if (IsSealed)
  27:                 throw new InvalidOperationException ("Cannot manipulate property values on a sealed DependencyObject");
  28:  
  29:             properties[dp] = null;
  30:         }
  31:  
  32:         //根據(jù)該依賴屬性DependencyPropertyKey,清除它的值
  33:         public void ClearValue(DependencyPropertyKey key)
  34:         {
  35:             ClearValue (key.DependencyProperty);
  36:         }
  37:  
  38:         //根據(jù)該依賴屬性名,強(qiáng)制值
  39:         public void CoerceValue (DependencyProperty dp)
  40:         {
  41:             PropertyMetadata pm = dp.GetMetadata (this);
  42:             if (pm.CoerceValueCallback != null)
  43:                 pm.CoerceValueCallback (this, GetValue (dp));
  44:         }
  45:  
  46:         public sealed override bool Equals (object obj)
  47:         {
  48:             throw new NotImplementedException("Equals");
  49:         }
  50:  
  51:         public sealed override int GetHashCode ()
  52:         {
  53:             throw new NotImplementedException("GetHashCode");
  54:         }
  55:  
  56:         //得到本地值的枚舉器
  57:         public LocalValueEnumerator GetLocalValueEnumerator()
  58:         {
  59:             return new LocalValueEnumerator(properties);
  60:         }
  61:  
  62:         //根據(jù)依賴屬性名獲取值
  63:         public object GetValue(DependencyProperty dp)
  64:         {
  65:             object val = properties[dp];
  66:             return val == null ? dp.DefaultMetadata.DefaultValue : val;
  67:         }
  68:         
  69:  
  70:         public void InvalidateProperty(DependencyProperty dp)
  71:         {
  72:             throw new NotImplementedException("InvalidateProperty(DependencyProperty dp)");
  73:         }
  74:         
  75:         //當(dāng)屬性值改變時(shí),觸發(fā)回調(diào)
  76:         protected virtual void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
  77:         {
  78:             PropertyMetadata pm = e.Property.GetMetadata (this);
  79:             if (pm.PropertyChangedCallback != null)
  80:                 pm.PropertyChangedCallback (this, e);
  81:         }
  82:  
  83:         //提供一個(gè)外界查看LocalValue的接口
  84:         public object ReadLocalValue(DependencyProperty dp)
  85:         {
  86:             object val = properties[dp];
  87:             return val == null ? DependencyProperty.UnsetValue : val;
  88:         }
  89:  
  90:         //根據(jù)依賴屬性名設(shè)置其值
  91:         public void SetValue(DependencyProperty dp, object value)
  92:         {
  93:             if (IsSealed)
  94:                 throw new InvalidOperationException ("Cannot manipulate property values on a sealed DependencyObject");
  95:  
  96:             if (!dp.IsValidType (value))
  97:                 throw new ArgumentException ("value not of the correct type for this DependencyProperty");
  98:  
  99:             ValidateValueCallback validate = dp.ValidateValueCallback;
 100:             if (validate != null && !validate(value))
 101:                 throw new Exception("Value does not validate");
 102:             else
 103:                 properties[dp] = value;
 104:         }
 105:  
 106:         //根據(jù)依賴屬性DependencyPropertyKey設(shè)置其值
 107:         public void SetValue(DependencyPropertyKey key, object value)
 108:         {
 109:             SetValue (key.DependencyProperty, value);
 110:         }
 111:  
 112:         protected virtual bool ShouldSerializeProperty (DependencyProperty dp)
 113:         {
 114:             throw new NotImplementedException ();
 115:         }
 116:  
 117:         //這里的注冊(cè)實(shí)質(zhì)是關(guān)聯(lián)propertyDeclarations
 118:         internal static void register(Type t, DependencyProperty dp)
 119:         {
 120:             if (!propertyDeclarations.ContainsKey (t))
 121:                 propertyDeclarations[t] = new Dictionary<string,DependencyProperty>();
 122:             Dictionary<string,DependencyProperty> typeDeclarations = propertyDeclarations[t];
 123:             if (!typeDeclarations.ContainsKey(dp.Name))
 124:             {
 125:                 typeDeclarations[dp.Name] = dp;
 126:                 //這里仍然有一些問題,期待各位共同探討解決
 127:             }
 128:             else
 129:                 throw new ArgumentException("A property named " + dp.Name + " already exists on " + t.Name);
 130:         }
 131:     }
 132: }

NET技術(shù)依賴屬性之“風(fēng)云再起”,轉(zhuǎn)載需保留來(lái)源!

鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請(qǐng)第一時(shí)間聯(lián)系我們修改或刪除,多謝。

主站蜘蛛池模板: 濉溪县| 赣榆县| 罗平县| 六安市| 永川市| 西城区| 阳原县| 德钦县| 临澧县| 海安县| 蓬溪县| 舟山市| 河源市| 永年县| 东阳市| 东源县| 五华县| 黎平县| 剑川县| 车险| 新疆| 铁岭市| 新巴尔虎右旗| 卓资县| 鄯善县| 黄龙县| 大港区| 通渭县| 凤冈县| 蒙自县| 正宁县| 自贡市| 义马市| 垣曲县| 龙州县| 黔南| 恩平市| 涟源市| 湛江市| 延安市| 报价|