C#筆記 – 分部類與分部方法
分部類
-
partial關鍵字
- 用於將類型源代碼分散到多個文件
-
實際上是在編譯之前在所有源文件合并在了一起,在一個文件中的代碼可以調用另外一個文件中的代碼
-
但每個獨立的成員必須完整地位於它所處的文件中
-
聲明必須相互兼容
-
任何文件都能指定要實現的接口(不一定在聲明的文件處實現)、基類、類型參數約束
-
如果多個文件都設定了基類,那它們必須是相同的(可以一個聲明,一個不聲明,但聲明了就必須相同),類型約束也是一樣。
-
兩個類型必須具有相同的訪問修飾符
-
-
在多個文件的情況下,成員和靜態變量的初始化不一定是按照順序發生的
-
用途:
-
連接設計器和其他代碼生成器。行用分部類型模型,代碼生成器可以擁有自由操作的文件,或者重寫整個文件
- 避免自動生成的代碼與人手編寫的代碼發生衝突
-
添加行為到類型變得非常簡單:重寫虛方法、添加帶有業務邏輯的新成員等等
- 方便讓不同程序員同時對一個類進行編輯,把類分成不同的邏輯單元
-
輔助重構
-
單元測試
-
分部方法
-
使用時機:使用了工具生成了C#源代碼文件,又想對裡面的行為進行定制
-
如果不使用分部方法,而是使用繼承的話
-
internal class Base { string m_Name; protected virtual void OnNameChanging(string value) { } public string Name { get { return m_Name; } set { OnNameChanging(value.ToUpper()); m_Name = value; } } } internal class Derived : Base { protected override void OnNameChanging(string value) { if (string.IsNullOrEmpty(value)) { return; } } } -
工具生成的類型必須是非密封的,所以也不能用於值類型(無法繼承)
-
也不能用於靜態方法,因為靜態方法不能重寫
-
在效率上,也會浪費資源
- 即使不去重寫定制的行為,但該行為仍然會被執行,也需要生成對應的IL代碼
-
-
使用分部方法
-
internal sealed partial class Base { string m_Name; partial void OnNameChanging(string value); public string Name { get { return m_Name; } set { OnNameChanging(value.ToUpper()); m_Name = value; } } } internal sealed partial class Base { partial void OnNameChanging(string value) { if (string.IsNullOrEmpty(value)) { return; } } } -
生成的類可以是靜態的,也可以是值類型
-
工具生成和開發者的代碼不是兩個獨立的類,也沒有繼承關係,就是一個類型定義的兩個部分
-
分部方法的聲明
-
工具
-
包含用partial關鍵字標記的聲明
-
無主體
-
-
開發者
-
包含用partial關鍵字標記的聲明
-
有主體
-
-
-
如果分部方法沒有被實現,編譯器就不會生成任何調用分部方法的IL指令以及元數據
-
使用規則
-
只能在分部類/結構中聲明
-
由於方法在運行時可能實際上並不存在(沒有被實現),所以分部方法的返回類型必須為void,參數也不能用out標記
- 可以有ref參數、泛型方法、實例/靜態方法、unsafe標記
-
分部方法的聲明和實現需具有完全一致的簽名,兩個方法和其中參數的特性都會被合并
-
如果沒有對應的實現部分,就不能讓委托引用該分部方法
-
總是為private
-
-
-
參考書目
- 《CLR via C#》(第4版) Jeffrey Richter
- 《深入理解C#》(第3版) Jon Skeet