C#筆記 – 類型基礎(一) C#類型系統

C#類型系統
  • C#的類型系統是靜態的、顯式的、安全的

靜態/動態類型
  • 靜態:每個變量都有一個特定的類型,而且在編譯時已知。只有該類型已知的操作才是允許的,由編譯器強制生效。

    • 靜態所指的是「表達式的編譯時類型」,因為它們使用不變的數據來分析哪些操作可用。

  • 動態:變量中含有值,但值不限於特定的類型,所以編譯器不能執行相同形式的檢查 => 通過在執行時動態檢查類型。

顯式/隱式類型
  • 顯/隱式類型區別只在靜態類型語言中有意義

  • 顯示類型:變量類型都必須在聲明中顯式指明

    • 非var的其他類型

  • 隱式類型:根據變量的用途來推斷變量類型

    • var

  • 無論是顯式還是隱式,類型在編譯時都是已知的,編譯時根據變量的用途的推斷;不同動態類型,動態類型是在執行時才判斷。

類型安全/不安全
  • 安全:必須進行類型的轉換才可以指明一種類型為另一種類型的數據

  • 不安全:不必進行任何轉換就可以把一個類型的值當作另一個完全不同的類型的值

    • 代碼有時會以錯誤的方式檢查值中的原始字節并解釋他們

類型轉換
  • 在C#中,向基類的轉換被認為是一種安全的隱式轉換;向派生類的轉換則需要顯式指定

    • class Employee{ }
      public static void Main()
      {
         //Object是Employee的基類,可隱式轉換
         Object o = new Employee();
         
         //Employee派生自Object
         //需要顯式轉換
         Employee e = (Employee)o;
      }
使用C#的is和as操作符轉型
  • is操作符檢查對象是否兼容於指定類型,返回一個bool值。

    • is操作符永遠不拋出異常

    • 如果對象引用為null,is總是返回false

    • Object o = new Object();
      bool b1 = o is Object; //True
      bool b2 = o is Employee; //False
  • is的使用

    • if(o is Employee)
      {
         Employee e = (Employee)o;
        ...
      }
    • 在該代碼中,CLR實際檢查了兩次對象的類型

      • 第一次,is首先檢查o是否兼容於Employee類型

      • 第二次,如果o兼容於Employee類型,在if語句內部,對o進行轉型時:(Employee)o。

        • CLR再次核實o是否可以顯式轉換成Employee

      • 加強了安全性,但是對性能有一定影響

        • CLR首先必須判斷變量(o)引用的對象的實際類型

        • 然後CLR必須遍歷繼承層次結構,用每個基類型去檢查指定的類型(Employee)

  • 為了提升is的性能,C#提供了as操作符

    • Employee e = o as Employee;
      if(e != null)
      {
        ...
      }
    • 如果使用了as操作符,CLR只須核實o是否兼容於Employee類型

      • 如果是,as返回對同一個對象的非null引用

      • 如果不是,as返回null

      • 因此as操作符造成CLR只校驗一次對象類型,if語句只檢查as返回值是否為null(比類型校驗要快得多)

    • as的工作方式與強制類型轉換一樣,但是as轉型失敗不會拋出異常,只是返回一個null

      • 強制類型轉換:(Employee) o;

參考書目

  • 《CLR via C#》(第4版) Jeffrey Richter
  • 《深入理解C#》(第3版) Jon Skeet