6.1 類型的各種成員 6.2 類型的可見性 public 全部可見 internal 程式集內可見(如忽略,預設為internal) 可通過設定 友元程式集 ,允許其它程式集訪問該程式集中的所有internal 類型.例如想允許強命名"Microsoft"程式集訪問本程式集內的internal類型 ...
6.1 類型的各種成員
6.2 類型的可見性
public 全部可見
internal 程式集內可見(如忽略,預設為internal)
可通過設定友元程式集,允許其它程式集訪問該程式集中的所有internal 類型.例如想允許強命名"Microsoft"程式集訪問本程式集內的internal類型:
using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("Microsoft,PublicKey=b77a5c56...1934e089")]
6.3 成員的可訪問性
private 成員只能由定義類型或任何嵌套類型中的方法訪問
protected 成員只能由定義類型、任何嵌套類型或者不管在什麼程式集中的派生類型中的方法訪問
internal 成員只能由定義程式集中的方法訪問
protected internal 成員可由任何嵌套類型、任何派生類型(不管在什麼程式集)或者定義程式集中的任何方法訪問
public 成員可由任何程式集的任何方法訪問
C#中,如果沒有顯式聲明成員的可訪問性,編譯器通常(但並不總是)預設選擇private(限制最大的那個)。
派生類重寫基類型定義的成員時,C#編譯器要求原始成員和重寫成員具有相同的可訪問性。
6.4 靜態類
靜態類必須直接從基類
System.Object
派生。靜態類不能實現任何介面。
靜態類只能定義靜態成員(欄位、方法、屬性和事件)
靜態類不能作為欄位、方法參數或局部變數使用。
6.5 分部類、結構和介面
- partial關鍵字告訴C#編譯器:類、結果或介面的定義源代碼可能要分散到一個或多個源代碼文件中(C#編譯器實現,和CLR無關)。
6.6 組件、多態和版本控制
C#關鍵字 | 類型 | 方法/屬性/事件 | |
---|---|---|---|
abstract | 表示不能構造該類型的實例 | 表示為了構造派生類型的實例,派生類型必須重寫並實現這個成員 | |
virtual | (不允許) | 表示這個成員可由派生類型重寫 | |
override | (不允許) | 表示派生類型正在重寫基類型的成員 | |
sealed | 表示該類型不能用作基類型 | 表示這個成員不能被派生類型重寫,只能將該關鍵字應用於重寫虛方法的方法 | |
new | 應用於嵌套類型、方法、屬性、事件、常量或欄位時,表示該成員與基類中相似的成員無任何關係 |
6.6.1 CLR如何調用虛方法、屬性和事件
call 該IL指令可調用靜態方法、實例方法和虛方法。
callvirt 該IL指令可調用實例方法和虛方法,不能調用靜態方法。
callvirt以多態方式調用虛實例方法,調用時,JIT編譯器會驗證變數的值是否為NULL,執行速度比call指令稍慢。
c#團隊認為,JIT編譯器應生成代碼來驗證發出調用的對象不為null.所以,C#用 callvirt 指令調用所有實例方法。
如果使用C#外的其它語言,定義了非虛方法後,將來永遠都不要把它更改為虛方法。這是因為某些編譯器會用 call 而不是 callvirt 調用非虛方法。如果方法從非虛變成虛,而引用代碼沒有重新編譯,會以非虛方式調用虛方法,造成應用程式無法預料。
設計類型時應儘量減少虛方法數量,因為:
- 調用虛方法的速度比調用非虛方法慢;
- JIT編譯器不能內嵌(inline)虛方法,這進一步影響性能;
- 虛方法使組件版本控制變得更脆弱;
- 定義基類型時,經常要提供一組重載的簡便方法(convenience method)。如果希望這些方法是多態的,最好的辦法就是使最複雜的方法成為虛方法,使所有重載的簡便方法成為非虛方法。
6.6.2 合理使用類型的可見性和成員的可訪問性
儘量使用關鍵字 sealed 將類顯式標記為密封,性能優於非密封類。
儘量將類指定為 internal (C#編譯器預設使用的就是 internal)
類的內部,將數據欄位定義為 private (C#預設),除了public,儘量連protected和internal也不用。
類的內部,避免使用protected或internal,因為這會使類型面臨更大的安全風險。virtual永遠最後才考慮。