轉(zhuǎn)帖|其它|編輯:郝浩|2010-10-28 14:34:41.000|閱讀 745 次
概述:C#中.我們可以利用部分類,將一個類分散到多個類文件中,這樣我們就可以多個開發(fā)者同時(shí)開發(fā)某個類庫,或者是擴(kuò)展其他開發(fā)者發(fā)布的類庫.甚至是代碼生成器生成的代碼,例如LINQ2SQL,ADO.NET EF等,以獲取更高效的開發(fā).
# 界面/圖表報(bào)表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
什么是部分類(Partial Class)?
C#中.我們可以利用部分類,將一個類分散到多個類文件中,這樣我們就可以多個開發(fā)者同時(shí)開發(fā)某個類庫,或者是擴(kuò)展其他開發(fā)者發(fā)布的類庫.甚至是代碼生成器生成的代碼,例如LINQ2SQL,ADO.NET EF等,以獲取更高效的開發(fā).
Re:Class和Class File的區(qū)別.這里的類是我們平時(shí)所說的普通類-Class,如抽象類,基類,子類等等.而類文件-Class File則是我們平時(shí)編寫類時(shí)所用到的文件,如C#的.cs,VB的.vb.
雖然部分類很好的解決了多個開發(fā)者同時(shí)開發(fā)而互不影響的問題,但其約束十分嚴(yán)格.開發(fā)者之間不能/很難彼此溝通,并且無法/很難修改對方的代碼.這意味著需要為對方提供很多掛鉤.這些掛鉤應(yīng)該以部分方法的方式實(shí)現(xiàn).而另一方的開發(fā)者可以選擇實(shí)現(xiàn)或不實(shí)現(xiàn).
擴(kuò)展現(xiàn)有類
實(shí)體框架的出現(xiàn),大大的減輕了我們的工作量,使我們把更多的重心放在邏輯實(shí)現(xiàn)上,而減少對于數(shù)據(jù)訪問的關(guān)注.例如我們可以使用LINQ2SQL,LINQ2SQL是一個輕型的實(shí)體框架.它生成了我們對數(shù)據(jù)層的訪問.但.有些時(shí)候,我們需要擴(kuò)展些自己的內(nèi)容,如方法/屬性等等.除了直接在生成的類文件中添加修改意外,我們還可以利用部分類擴(kuò)展我們所需的功能,前者當(dāng)每次我們跟新實(shí)體時(shí).你所擴(kuò)展的內(nèi)容都會消失.而部分類依然能很好的為你服務(wù).
提供部分方法
為部分類提供最有效的鉤子就是部分方法.它和接口的方法聲明很相似.
關(guān)鍵字partial+void+方法名+方法參數(shù).
partial void ReportValueChanging(RequestChange args);
由于部分方法可能成為類的一部分(實(shí)現(xiàn)),也可能不成為類的一部分(不實(shí)現(xiàn)),所以C#本身對于部分方法給出了一些限制.
1.返回類型必須為void.
2.部分方法不能為抽象/虛方法.
3.部分方法不能用來實(shí)現(xiàn)接口.
4.參數(shù)列表不能包含任何out參數(shù),因?yàn)榫幾g器無法初始化這些out參數(shù).
我們利用部分方法來讓用戶件事或修改類的行為:修改方法,事件處理程序及構(gòu)造函數(shù).
修改方法
修改方法是指那些將要修改類中對外可見的狀態(tài)的方法.我們可以將其理解為任何狀態(tài)的變化,由于另一個類文件的部分類實(shí)現(xiàn)依然是類的一部分.所以我們可以完全控制到該類的所有內(nèi)部狀態(tài).
一般而言,修改方法應(yīng)該為類提供兩個部分方法.第一個在修改前調(diào)用,用來讓另一方(另一開發(fā)者)能夠進(jìn)行合法性驗(yàn)證等等.第二個方法應(yīng)該在修改狀態(tài)后調(diào)用,用來讓另一方相應(yīng)這個狀態(tài)的變化.
public partial class GeneratedStuff { private struct ReportChange { public readonly int OldValue; public readonly int NewValue; public ReportChange(int oldValue, int newValue) { this.OldValue = oldValue; this.NewValue = newValue; } } private class RequestChange { public ReportChange Values { get; set; } public bool Cancel { get; set; } } partial void ReportValueChanging(RequestChange args); partial void ReportValueChanged(ReportChange values); private int storage = 0; public void UpdateValue(int newValue) { RequestChange updateArgs = new RequestChange { Values = new ReportChange(storage, newValue) }; ReportValueChanging(updateArgs); if (!updateArgs.Cancel) { storage = newValue; ReportValueChanged(new ReportChange(storage, newValue)); } } }
如果另一個部分類沒有提供兩個部分方法的實(shí)現(xiàn),那么C#編譯器將移除該調(diào)用.生成方法如下
public void UpdateValue(int newValue) { RequestChange updateArgs = new RequestChange { Values = new ReportChange(this.storage, newValue) }; if (!updateArgs.Cancel) { this.storage = newValue; } }
并且,兩個部分方法也一并移除了.
我們可以實(shí)現(xiàn)掛鉤如下
public partial class GeneratedStuff { partial void ReportValueChanging(GeneratedStuff.RequestChange args) { if (args.Values.NewValue < 0) { //dosomething... } else { //dosomething... } } partial void ReportValueChanged(GeneratedStuff.ReportChange values) { //dosomething... } }
這里,我們通過一個取消標(biāo)記來讓開發(fā)者可以取消某個修改動作,你也可以通過拋出異常得到同樣的效果.但.推薦使用布爾型的取消標(biāo)記,因?yàn)檫@樣更加輕量一些
事件處理程序
實(shí)際上,事件的處理程序和上面的方法修改并無多大的區(qū)別.你所需要做的.僅僅只是添加一個委托事件而已.實(shí)現(xiàn)了類似控件的事件機(jī)制.
構(gòu)造函數(shù)擴(kuò)展
無論是生成的代碼,還是我們手工編寫的代碼.我們都無法預(yù)計(jì)調(diào)用類時(shí)外部將會調(diào)用哪個構(gòu)造函數(shù).所以.我們只能在內(nèi)部做一些手腳.例如
public partial class GeneratedStuff
{
partial void Initialize();
public GeneratedStuff() :
this(0)
{ }
public GeneratedStuff(int someValue)
{ this.storage = someValue; Initialize();
}
}
注意!Initialize在最后調(diào)用,這樣就有了一次檢查當(dāng)前對象狀態(tài)的機(jī)會,可以進(jìn)行必要的修改,或是對于不符合要求時(shí)拋出異常等等.實(shí)際上.這種構(gòu)造函數(shù)重載也有效的提升你的代碼質(zhì)量(對于不同的構(gòu)造函數(shù),結(jié)果IL都會生成不同的函數(shù)塊.而這種重構(gòu)法最后其實(shí)真正生成的函數(shù)塊只有一個)
尾聲
經(jīng)過以上的闡述,相信我們已經(jīng)更了解部分類是怎樣煉成的了.只有更好的了解其背后的一系列"小動作",才有助于我們更好的提升,寫出更有質(zhì)量的代碼
本站文章除注明轉(zhuǎn)載外,均為本站原創(chuàng)或翻譯。歡迎任何形式的轉(zhuǎn)載,但請務(wù)必注明出處、不得修改原文相關(guān)鏈接,如果存在內(nèi)容上的異議請郵件反饋至chenjj@fc6vip.cn
文章轉(zhuǎn)載自:網(wǎng)絡(luò)轉(zhuǎn)載