← 筆記

C#筆記 – CLR的執行模型(三) 類庫及語言規範

Framework類庫
  • .NET Framework 包含 Framework類庫(Framework Class Library, FCL)
    • FCL是一組DLL程序集的統稱,類型數量太多,因此相關的類型會被放到單獨的命名空間,如:
      • System(包含了每個應用程序都要用到的基本類型:Object/…)
      • System.Data
      • System.IO
      • System.Text
      • 等等
通用類型系統
  • CLR一切都圍繞類型展開,類型是CLR的根本
    • 類型向應用程序和其他類型公開了功能
    • 類型使兩種編程語言寫的代碼之間可以溝通
  • Microsoft對「類型」的定義和行為制定了規範——「通用類型系統」(Common Type System, CTS)
    • Microsoft把CTS和.NET Framework的其他組件已交給ECMA完成標準化工作,最後形成的標準稱為「公共語言基礎結構」(Common Language Infrastructure, CLI)
CTS規範
  • 一個類型可包含0個或多個成員
    • 字段
      • 作為對象狀態的數據變量
    • 方法
      • 針對對象執行操作的函數
      • 方法有一個名稱、簽名、一個/多個修飾符
        • 簽名指定參數數量及其類型、返回值及其類型
    • 屬性
      • 對於調用者像是字段
      • 對於實現者像是方法
    • 事件
      • 實現對象之間的通知機制
  • 可見性規則及訪問規則
    • private
      • 同一個類內可訪問
    • family
      • 派生類可訪問,即使不在同一個程序集中
      • 在C#中,等價於protected
    • family and assembly
      • 派生類可訪問,且需要在同一程序集中
      • C#不存在該限制
    • assembly
      • 同一程序集中可訪問
      • C#中,等價於internal
    • family or assembly
      • 派生類或同一程序集中可訪問
      • C#中,等價於 protected internal
    • public
      • 完全公開
  • 「代碼的語言」與「代碼的行為」
    • 無論使用哪一種語言,類型的行為都完全一致
    • 語言會以開發者自身最熟悉的方式公開它的語法和類型規則,在編譯成程序集時,它會再將其特有的語法映射到IL(CLR的「語言」)
    • 最終都是由CLR的CTS來定義類型的行為
公共語言規範
  • CLR集成了所有語言,用一種語言創建的對象在另一種語言中,和用後者創建的對象具有相同地位,使得不同語言創建的對象之間可以進行相互通信
    • 各種編程語言之間存在極大區別,要創建很容易從其他編程語言中訪問的類型,只能從自己的語言中挑選其他所有語言都支持的功能 => 公共語言規範(Common Language Specification,CLS),它定義了一個最小功能集。
    • 任何編譯器只要支持這個功能集,生成的類型就能兼容其他符合CLS、面向CLR的語言生成的組件
  • 不同於CLR/CTS,CLS定義的只是一個子集
    • 如果開發類型和方法時,希望它對外「可見」,能從符合CLS的任何編程語言中訪問,就需要遵守CLS定義的規則
  • CLR/CTS提供的是一個功能集,如果開發者用IL匯編寫程序,就可以使用CLR/CTS全部功能,一般語言(如C#)只公開了部分的功能
    • CLS定義了不同的語言(如C#、Fortan、Visual Basic)之間都必須支持的最小功能集

  • 在CLR中,類型的每個成員要麼是字段(數據),要麼是方法(行為)

    • 每一種編程語言都必須能訪問字段和調用方法
      • 在編程語言中,往往會對字段和方法進行了額外的抽象,從而使編程變得更簡單。比如以下概念的公開:
        • 枚舉
        • 數組
        • 屬性
        • 委托
        • 構造器
        • 操作符重載
        • 等等
      • 編譯器在源代碼中遇到其中任何一樣,都必須將其轉換成字段和方法,使CLR和其他任何編程語言可以訪問這些構造
        • 如下例的源碼與IL代碼:
        •   using System;
            
            internal sealed class Test
            {
                //Constructor
                public Test() { }
            
                //終結器
                ~Test() { }
            
                //操作符重載
                public static bool operator == (Test t1, Test t2) { return true; }
                public static bool operator != (Test t1, Test t2) { return false; }
                public static Test operator + (Test t1, Test t2) { return null; }
            
                //屬性
                public string AProperty
                {
                    get { return null; }
                    set { }
                }
            
                //索引器
                public string this[int x]
                {
                    get { return null; }
                    set { }
                }
            
                //事件
                event EventHandler AnEvent;
            }

  • 當中大部分的構造都被編譯成了.method(方法)

    • op_Addition

      .method public hidebysig specialname static 
              class CLR_Via_CSharp_4._0.Test  op_Addition(class CLR_Via_CSharp_4._0.Test t1,
                                                          class CLR_Via_CSharp_4._0.Test t2) cil managed
      {
        // 程式碼大小       7 (0x7)
        .maxstack  1
        .locals init (class CLR_Via_CSharp_4._0.Test V_0)
        IL_0000:  nop
        IL_0001:  ldnull
        IL_0002:  stloc.0
        IL_0003:  br.s       IL_0005
        IL_0005:  ldloc.0
        IL_0006:  ret
      } // end of method Test::op_Addition
    • get_Item

      .method public hidebysig specialname instance string 
              get_Item(int32 x) cil managed
      {
        // 程式碼大小       7 (0x7)
        .maxstack  1
        .locals init (string V_0)
        IL_0000:  nop
        IL_0001:  ldnull
        IL_0002:  stloc.0
        IL_0003:  br.s       IL_0005
        IL_0005:  ldloc.0
        IL_0006:  ret
      } // end of method Test
    • 還有一些被編譯成了.field(字段)

      • AnEvent : private class [System.Runtime]System.EventHandler
        •   .field private class [System.Runtime]System.EventHandler AnEvent
            .custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) 
            .custom instance void [System.Diagnostics.Debug]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [System.Diagnostics.Debug]System.Diagnostics.DebuggerBrowsableState) = ( 01 00 00 00 00 00 00 00 )
    • 例子各構造與CLR字段/方法對應關係表

      • 成員成員類型對應的編程語言構造
        AnEvent字段事件
        .ctor方法構造器
        Finalize方法終結器
        add_AnEvent方法事件的add方法
        get_AProperty方法屬性的get方法
        get_Item方法索引器的get方法
        op_Addition方法+操作符的重載方法
        op_Equality方法==操作符的重載方法
        op_Inequality方法!=操作符的重載方法
        remove_AnEvent方法事件的remove方法
        set_AProperty方法屬性的set方法
        set_Item方法索引器的set方法
    • 另外還有.class、.custom、AnEvent、AProperty、Item的節點不屬於字段/方法

      • 這些節點標識了類型的其他元數據,它們只提供了一些額外信息,供CLR、編程語言或工具訪問
      • 在這些節點裡面,往往包含了指向其他方法節點的信息
        • AProperty

          •   .property instance string AProperty()
              {
                //指向了get_AProperty方法
                .get instance string CLR_Via_CSharp_4._0.Test::get_AProperty()
                //指向了set_AProperty方法
                .set instance void CLR_Via_CSharp_4._0.Test::set_AProperty(string)
              } // end of property Test::AProperty
        • AnEvent

          •   .event [System.Runtime]System.EventHandler AnEvent
              {
                //指向了add_AnEvent方法
                .addon instance void CLR_Via_CSharp_4._0.Test::add_AnEvent(class [System.Runtime]System.EventHandler)
                //指向了remove_AnEvent方法
                .removeon instance void CLR_Via_CSharp_4._0.Test::remove_AnEvent(class [System.Runtime]System.EventHandler)
              } // end of event Test::AnEvent

參考書目

  • 《CLR via C#》(第4版) Jeffrey Richter