好一陣子沒寫文章了, 來寫點關於類別的故事好了. 為什麼題目不叫型別外傳而叫類別外傳呢 ? 因為這樣就可以排除掉列舉和結構型別, 簡單說就是懶啦. 這系列不打算講甚麼類別是參考型別這類的問題, 因為這個議題很多人討論過了, 我想要討論一些比較無趣的課題.
好一陣子沒寫文章了, 來寫點關於類別的故事好了. 為什麼題目不叫型別外傳而叫類別外傳呢 ? 因為這樣就可以排除掉列舉和結構型別, 簡單說就是懶啦. 這系列不打算講甚麼類別是參考型別這類的問題, 因為這個議題很多人討論過了, 我想要討論一些比較無趣的課題.
想寫這篇文的原因來自於我常常問的一個問題 : 『類別本身在記憶體裡面會不會形成一個物件 ? (我所指的是類別本身, 而不是呼叫 new 由此類別產生的執行個體)』. 有很大的機率會得到 『不會』這個答案, 但事實上的答案是『會的』. 當你使用到某個類別的時候, 在記憶體中會為這個類別產生一個型別物件, 這個型別物件的型別就是 Type Class (試著快速念三遍…).
對於型別物件有兩個特性 (1) 當你使用到該型別時, CLR 會幫你產生型別物件 (2) 每一種型別的型別物件在該 AppDomain 只會被產生一次, 也就是在記憶體中僅會有一份. 試著先記住這兩件事, 後面我會證明這兩個特性.
型別物件的存在
其實要證明型別物件存在很簡單, C# 有個 typeof() 運算式, Object 有個方法叫 GetType(), 這兩個方法回傳的型別是甚麼 ? 就是 System.Type, 意即這兩個方法回傳的值就是指向該型別的型別物件. 既然你可以用變數存取它, 表示它必然以某種物件的形式存在於記憶體. 否則你如何存取 ?
記憶體中只會存在一份該型別的型別物件
要證明這件事, 只要用上 Object.ReferenceEquals 方法就可以證明了, 這個方法比較的是兩個變數所指向的物件是不是位在同一個位址上, 所以簡單的程式碼就可以證明獨一的論述.
1: namespace ConsoleApplication1
2: {
3: class Program
4: {
5: static void Main(string[] args)
6: {
7: Type t1 = typeof(Class1);
8: Class1 c = new Class1();
9: Type t2 = c.GetType();
10: Console.WriteLine(Object.ReferenceEquals(t1, t2));
11: Console.ReadLine();
12: }
13: }
14:
15: public class Class1
16: {
17: public string str;
18: public Class1()
19: {
20:
21: }
22: }
23: }
這個答案是 True, 也就是 t1, t2 指向的物件是同一個. 這篇先就此打住, 下回來談點別的.