公共型別系統(Comnioii Type System, CTS)定義了什麼是型別,以及每個型別可以擁有的成員和行為。
之所以稱它是通用的,是因為它對所有 .NET 語言都適用。CTS 是保證 C# 語言型別安全的前提。
前邊已經說過,CTS 只是一個規範,並沒有限制它的實現方式。CLR 可以看作是 CTS 的一種實現,它符合上面給出的連結上的所有要求。其他的實現包括 Mono, Rotor 等。
下表列出了 .NET 中一些基礎名詞及縮寫,以及這些名詞之間的相互關係。
名詞 |
說明 |
VES(虛擬執行系統) |
負責為某種語言在執行時提供一切必須的上下文和記憶體、執行緒管理、字串駐 留、垃圾回收、即時編譯等服務。CLR 是它的一個實現。可以用執行時(Runtime)代稱。一個 VES 的實現可以提供上面所說的所有服務,也可以只提供部分服務 |
IL(中間語言) |
.NET 框架語言第一步編譯的目標語言。它會再通過 JIT 編譯器編譯為機器碼 |
CTS(公共型別系統) |
CLI 的一部分,描述了各種型別應該具有怎樣的行為以及可以擁有什麼樣的成員 |
CLS(公共語言規範) |
CTS 的一部分,描述了一個框架語言需要擁有的最小功能集 |
CLI(公共語言基礎設施) |
上面所有的彙總。它包括了 VES、IL、CTS、CLS的定義,還規定了後設資料應該包括什麼等等。目前,主流的 CLI 實現有 .NET 編譯器、微軟 XNA、Rotor (即 Shared Source CLI)等等。可以在 ECMA334 和 ECMA335 這兩份檔案中找到 CLI 的全部內容 |
型別指的是集合{類,結構,介面,列舉,委託}中的任意一個成員。
型別(type)和 類(class)不同,後者是前者的一個特殊情況。
任何擁有某型別的值(value)稱為某型別的一個範例(instance)。
在 .NET 中,對任何值的使用(作為引數傳遞或操作)都需要首先明確這個值的型別是什麼。
介面和委託都是一種特殊的類,而結構可以看作一個輕量級的類。
型別可以被分為值型別(結構和列舉)以及參照型別(類、介面、指標、.字串、委託、陣列),沒有第三種情況。特別的,指標屬於參照型別。
型別可以擁有 0 或多個成員,這些成員可以簡單地分為欄位、方法和巢狀型別。
欄位成員包括:
1) 常數(const)
一個隱式為靜態和唯讀的成員。由於它一定是靜態的,所以它屬於類 型本身。
2) 欄位(field)和屬性(property)
刻畫型別的基本性質。靜態的欄位和屬性屬於型別本身。
屬性還分為無參屬性和有參屬性(索引器),並包括兩個方法。
3) 事件(event)
事件在物件以及其他相關物件之間實現了一個通知機制。
例如,利用按鈕提供的一個事件,可以在按鈕被單擊之後通知其他物件。
實際上也可以將其看作一種方法,只不過不能自定義。
其中,屬性和事件自帶的方法位於附加的後設資料中,無法自定義和修改。
方法成員包括:
1) 建構函式(constructor)和解構函式(destructor)
用於型別初始化和型別的垃圾回收。 建構函式又可以分為靜態的和範例的。
2) 方法(method)
型別的方法可以視為它提供的功能,分為靜態的和範例的。
3) 操作符過載
一種特殊的方法,它用於重寫操作符的定義。
可以在型別中定義其他型別,這稱為巢狀型別。例如,類中可以含有委託和另一個類。不過,巢狀型別的使用有很多限制。
CTS 也規定了某些型別只能擁有上述成員的一小部分而不是全部。例如,列舉型別不可以擁有自己的方法,屬性和事件。
C# 支援 6 種型別存取修飾符。存取範圍由大到小排序為:
1) public:沒有限制。
2) protected internal:只能在所在程式集、定義的型別或派生型別進行存取。
3) internal:只能在所在程式集存取。
4) private protected: C# 7.2 新增的存取修飾符,等同於5和6中滿足任意一個。
5) protected:只能由定義的型別或派生型別進行存取。
6) private:只能由定義的型別進行存取。
所有修飾符都可以修飾型別成員,而對應於直接定義在名稱空間下面的型別,則只有 public 和 internal 是可以使用的(除非型別巢狀於另一個更大的型別中)。
顯然,為一個非巢狀類加上 private 和 protected 是毫無意義的。
所以,除了 public 和 internal,其他四種修飾符不能作用於非巢狀類。
由 internal 修飾的類中的方法只能被同程式集的其他物件存取。
如果一個程式集 A 中有一個 internal 的型別 B,它含有方法 C,那麼程式集 D 中的程式碼不能呼叫方法 C,即使 C 是 public 的。
因為型別 B 對於程式集 D 不可見。程式集 D 也可以定義自己的型別 B,它被視為和程式集 A 中的 B 不同。
型別的存取修飾符體現了封裝性,即開發者可以控制型別中哪些方法和成員對外界是否可見,從而令外界不需要知道它們永遠不會存取或呼叫的成員。
如果沒有指定存取修飾符,型別的存取修飾符預設為 internal,型別成員則預設為 private(都是限制最大的那個)。