淺談partial class(區域性類)
C# 2.0 可以將類、結構或介面的定義拆分到兩個或多個原始檔中,在類宣告前新增partial關鍵字即可。
例如:下面的PartialTest類
class PartialTest
{
string Str_FieldTest;
int Int_FieldTest;
public void DoTest()
{
Debug.Print("Test");
}
}
可在不同原始檔中寫成下面形式:
一個檔案中寫:
partial class PartialTest
{
string Str_FieldTest;
int Int_FieldTest;
}
另一個檔案中寫:
partial class PartialTest
{
public void DoTest()
{
Debug.Print("Test");
}
}
什麼情況下使用分部類?
– 處理大型專案時,使一個類分佈於多個獨立檔案中可以讓多位程式設計師同時對該類進行處理(相當於支援並行處理,很實用);
– 使用自動生成的源時,無需重新建立原始檔便可將程式碼新增到類中。Visual Studio 在建立Windows 窗體、Web 窗體時都使用此方法。你不用編輯Visual Studio 所建立的檔案,便可建立使用這些類的程式碼。換句話說:系統會自動建立一個檔案(一般記錄的是窗體及窗體中的控制元件的屬性),另一個或幾個檔案記錄的是使用者自己編寫的程式碼。這兩部分分開可以使結構顯得非常清晰,使用者只需關注自己負責的那部分就行了(需要的話,這兩部分可以互相呼叫)。等到了編輯執行的時候,系統會自動將這兩部分合成一個檔案。
使用Partial需要注意以下一些情況:
1. 使用partial 關鍵字表明可在名稱空間內定義該類、結構或介面的其他部分
2. 所有部分都必須使用partial 關鍵字
3. 各個部分必須具有相同的可訪問性,如public、private 等
4. 如果將任意部分宣告為抽象的,則整個型別都被視為抽象的
5. 如果將任意部分宣告為密封的,則整個型別都被視為密封的
6. 如果任意部分宣告繼承基類時,則整個型別都將繼承該類
7. 各個部分可以指定不同的基介面,最終型別將實現所有分部宣告所列出的全部介面
8. 在某一分部定義中宣告的任何類、結構或介面成員可供所有其他部分使用
9.巢狀型別可以是分部的,即使它們所巢狀於的型別本身並不是分部的也如此。如下所示:
class Container
{
partial class Nested
{
void Test1();
}
partial class Nested
{
void Test2();
}
}
使用分佈類的一些限制:
1. 要作為同一型別的各個部分的所有分部型別定義都必須使用partial 進行修飾。如下所示:
public partial class A { }
public class A { } // Error, must also be marked partial
2. partial 修飾符只能出現在緊靠關鍵字class、struct 或interface前面的位置(列舉或其它型別都不能使用partial);
3. 要成為同一型別的各個部分的所有分部型別定義都必須在同一程式集和同一模組(.exe 或.dll 檔案)中進行定義。分部定義不能跨越多個模組;
4. 類名和泛型型別引數在所有的分部型別定義中都必須匹配。泛型型別可以是分部的。每個分部宣告都必須以相同的順序使用相同的引數名。
------------------------------------------------------------------------------------------------------------------------------------------
partial class擴充套件功能新思路
開閉原則:“對修改封閉,對擴充套件開放”。在面向物件的系統中,通過類的繼承實現擴充套件。.net中提供的partial class提供了擴充套件類的新思路。
一、應用場景
可以使用partial class的場景很多。這裡分析一個ORM的例子。
系統中有一個Cat類,屬性ID、Age、Weight都需要儲存到資料庫中,一個資訊系統中常見的需求。通過讀取資料庫的結構,可以用工具生成Cat類的程式碼。並且ORM框架支援了從資料庫資訊生成Cat物件。
現在的Cat什麼動作都沒有,客戶說,我們需要一個Miaow()的函式。這時就需要對ORM生成的Cat類進行擴充套件了。
可以肯定地一點是,我們不能修改自動生成的程式碼,因為這會牽涉到資料庫結構與程式碼同步的問題。解決這個需求有兩種方法:繼承方式擴充套件,partial class擴充套件。
二、繼承方式擴充套件
工具自動生成一個CatBase類,這個類只有屬性,嵌入到ORM框架中。既然需要擴充套件功能,很容易想到對這個基類繼承,於是有了Cat類。Cat類如願以償地有了Miaow()函式。
以前系統中用的是CatBase的例項,現在建立CatBase例項的地方需要改為建立Cat的例項。這個問題讓ORM框架解決吧。
客戶的需求實現了,我們自己的程式碼生成也沒有遭到破壞,任務完成。
三、partial class擴充套件
partial class簡單地說就是可以將一個類的程式碼寫到兩個或多個程式碼檔案中。編譯器在編譯的過程中將這幾個檔案組合起來一起編譯。一個很酷的技術。
工具生成的Cat類仍然不變。既然需要增加函式,那麼在新建一個程式碼檔案,將Miaow()函式寫出來就可以。需要做的僅僅是將類的宣告由class改為partial class,任務完成。
四、對比分析
兩種思路都可以實現需求。孰優孰劣需要仔細分析一下。
例項建立:partial class更加簡潔。
系統複雜度:對於系統來說,partial class方式下只存在一個類,而繼承方式有兩個類。
繼承邏輯:從邏輯上講,Cat並不需要一個基類CatBase,這樣做僅僅是因為在程式碼構建過程中的一個限制。
維護性:兩種方式下都會存在兩個程式碼檔案,維護成本並沒有區別。
可讀性:兩個Cat檔案確實讓人費解。
整體上說,使用partial class更加優雅一些。
“繼承”的這種方式比較符合傳統的思維習慣,而partial class到底是不是滿足開閉原則呢,這點確實不好說。不過在軟體構建上,我是一個實用主義者,哪種方式好用就用哪一種。
在ORM的場景中,partial class更加好一些,但有的時候,兩個類之間確實就存在繼承關係,那麼就必須用到繼承了。雖然絕大多數情況下,都需要繼承方式,但是既然有了partial class技術,我們在做設計時也需要考慮這個思路。
在VS2005中,Form、DataSet都使用了partial class方式,原理和這個一樣。但是要將這個原理推廣到“業務實體”中,可能在理解上需要有所突破。
使用partial class確實會帶來可讀性的損失,尤其是一個類分佈在很多個檔案中的時候,所以檔案的命名最好是有一個規範來保證。