C#中的object類型


OBJECT類型

object(System.Object)是所有類型的終極父類,所有類型都可以向上轉換為object。

下面我們看一個例子

public class Stack
{
    int position;
    object[] data = new object[10];
    public void Push (object obj) { data[position++] = obj; }
    public object Pop() { return data[--position]; }
}

這是一個后進先出的這么一個棧,因為是object類型,所以你可以Push和Pop任意的類型到這個棧里

Stack stack = new Stack();
stack.Push ("sausage");
string s = (string) stack.Pop(); // 向下轉換,顯式的轉換一下

Console.WriteLine (s); // sausage

object是引用類型,但值類型可以轉換為object,反之亦然。(類型統一)

stack.Push (3);
int three = (int) stack.Pop();

在值類型和object之間轉換的時候,CLR必須執行一些特殊的工作,以彌補值類型和引用類型之間語義上的差異,這個過程就叫做裝箱和拆箱。

 

裝箱(boxing)

裝箱就是把值類型的實例轉換為引用類型的實例的動作,目標引用類型可以是object,也可以是某個接口

int x = 9;
object obj = x; // 把int值裝箱

 

拆箱(unboxing)

拆箱正好和裝箱相反,把對象轉換為原來的值類型

int y = (int)obj; // 還原int值

拆箱需要顯式的轉換

拆箱過程中,運行時會檢查這個值類型和object對象的真實類型是否匹配,如果不匹配就拋出InvalidCastException

object obj = 9; // 9 在這里是int類型
long x = (long) obj; // InvalidCastException

下面的轉換就是可以的,int類型可以隱式的轉換為long類型,但是像上面的直接拆箱就不可以:

object obj = 9;
long x = (int) obj;

裝箱對於類型統一是非常重要的,但是系統設計還是不夠完美,比如數組和泛型只支持引用轉換,不支持裝箱

object[] a1 = new string[3]; // 可以的
object[] a2 = new int[3]; // 會報錯

 

裝箱拆箱的復制

  • 裝箱會把值類型的實例復制到一個新的對象
  • 拆箱會把這個對象的內容再復制給一個值類型的實例

看個例子:

int i = 3;
object boxed = i;
i = 5;
Console.WriteLine (boxed); // 3

 

靜態和運行時類型檢查

C#的程序既會做靜態的類型檢查(編譯時),也會做運行時的類型檢查(CLR)

靜態檢查:就是不運行程序的情況下,讓編譯器保證你的程序的正確性,比如 int x = "5"; 這么寫肯定是不行的

運行時的類型檢查由CLR執行,發生在向下的引用轉換或拆箱的時候。

object y = "5";
int z = (int) y; // 運行時報錯,向下轉換失敗

運行時檢查之所以可行是因為每個在heap上的對象內部都存儲了一個類型token。這個token可以通過調用object的GetType()方法來獲取。

 

GetType方法與typeof操作符

所有C#的類型在運行時都是以System.Type的實例來展現的

有兩種方式可以獲得System.Type對象:一是在實例上調用GetType()方法;第二個是在類型名上使用typeof操作符。

GetType是在運行時被算出的,typeof是在編譯時被算出的(靜態)(當涉及到泛型類型參數時,它是由JIT編譯器來解析的)

 

System.Type

System.Type的屬性有:類型名稱、Assembly、基類等等。直接看例子:

using System;
public class Point { public int X, Y; }
class Test
{
    static void Main()
    {
        Point p = new Point();
        Console.WriteLine (p.GetType().Name); // Point
        Console.WriteLine (typeof (Point).Name); // Point
        Console.WriteLine (p.GetType() == typeof(Point)); // True
        Console.WriteLine (p.X.GetType().Name); // Int32
        Console.WriteLine (p.Y.GetType().FullName); // System.Int32
    }
}

 

ToString方法

ToString()方法會返回一個類型實例的默認文本表示

所有的內置類型都重寫了該方法

int x = 1;
string s = x.ToString(); // s is "1"

我們可以在自定義的類型上重寫ToString()方法,如果你沒有重寫該方法,那么就會返回該類的名稱,是一個包括命名空間的全名

public class Panda
{
    public string Name;
    public override string ToString() => Name;
}
   
 ...

Panda p = new Panda { Name = "Petey" };
Console.WriteLine (p); // Petey

當你調用一個被重寫的object成員的時候,例如在值類型上直接調用ToString()方法,這時候就不會發生裝箱操作,但是如果你進行了轉換,那么裝箱操作就會發生

int x = 1;
string s1 = x.ToString(); // 這里就沒有發生裝箱
object box = x;
string s2 = box.ToString(); // 調用的就是裝箱后的值

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM