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和其他任何編程語言可以訪問這些構造

      • 如下例的源碼與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::get_Item
      • 還有一些被編譯成了.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