<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      [你必須知道的.NET]第二十三回:品味細節,深入.NET的類型構造器

      《你必須知道的.NET》網站 | Anytao技術博客 

      [你必須知道的.NET]第二十三回:品味細節,深入.NET的類型構造器

      發布日期:2008.11.2 作者:Anytao
      ? 2008 Anytao.com ,Anytao原創作品,轉貼請注明作者和出處。

      說在,開篇之前
      今天Artech兄在《關于Type Initializer和 BeforeFieldInit的問題,看看大家能否給出正確的解釋》一文中讓我們認識了一個關于類型構造器調用執行的有趣示例,其中也相應提出了一些關于beforefieldinit對于類型構造器調用時機的探討,對于我們很好的理解類型構造器給出了一個很好的應用實踐體驗。
      認識類型構造器,認識beforefieldinit,更深入關注CLR執行機理,品味細節之美。
      1 引言

      今天Artech兄在《關于Type Initializer和 BeforeFieldInit的問題,看看大家能否給出正確的解釋》一文中讓我們認識了一個關于類型構造器調用執行的有趣示例,其中也相應提出了一些關于beforefieldinit對于類型構造器調用時機的探討,對于我們很好的理解類型構造器給出了一個很好的應用實踐體驗。
      作為補充,本文希望從基礎開始再層層深入,把《關于Type Initializer和 BeforeFieldInit的問題,看看大家能否給出正確的解釋》一文中沒有解釋的概念和原理,進行必要的補充,例如更全面的認識類型構造器,認識BeforeFieldInit。并在此基礎上,探討一點關于類型構造器的實踐應用,同時期望能夠回答其中示例運行的結果。
      廢話少說,我們開始。

      2 認識對象構造器和類型構造器

      在.NET中,一個類的初始化過程是在構造器中進行的。并且根據構造成員的類型,分為類型構造器(.cctor)和對象構造器(.ctor), 其中.cctor和.ctor為二者在IL代碼中的指令表示。.cctor不能被直接調用,其調用規則正是本文欲加闡述的重點,詳見后文的分析;而.ctor會在類型實例化時被自動調用。
      基于對類型構造器的探討,我們有必要首先實現一個簡單的類定義,其中包括普通的構造器和靜態構造器,例如

          // Release : code01, 2008/11/02                
          // Author  : Anytao, http://www.anytao.com 
          public class User
          {
              static User()
              {
                  message = "Initialize in static constructor.";
              }
       
              public User()
              {
                  message = "Initialize in normal construcotr.";
              }
       
              public User(string name, int age)
              {
                  Name = name;
                  Age = age;
              }
       
              public string Name { get; set; }
       
              public int Age { get; set; }
       
              public static string message = "Initialize when defined.";

      我們將上述代碼使用ILDasm.exe工具反編譯為IL代碼,可以很方便的找到相應的類型構造器和對象構造器的影子,如圖

      然后,我們簡單的來了解一下對象構造器和類型構造器的概念。

      • 對象構造器(.ctor)
      在生成的IL代碼中將可以看到對應的ctor,類型實例化時會執行對應的構造器進行類型初始化的操作。
      關于實例化的過程,設計到比較復雜的執行順序,按照類型基礎層次進行初始化的過程可以參閱《你必須知道的.NET》7.8節 “動靜之間:靜態和非靜態”一文中有詳細的介紹和分析,本文中將不做過多探討。
      本文的重點以考察類型構造器為主,所以在此不進行過多探討。
      • 類型構造器(.cctor)
      用于執行對靜態成員的初始化,在.NET中,類型在兩種情況下會發生對.cctor的調用:
      • 為靜態成員指定初始值,例如上例中只有靜態成員初始化,而沒有靜態構造函數時,.cctor的IL代碼實現為:
      .method private hidebysig specialname rtspecialname static 
              void  .cctor() cil managed
      {
        // Code size       11 (0xb)
        .maxstack  8
        IL_0000:  ldstr      "Initialize when defined."
        IL_0005:  stsfld     string Anytao.Write.TypeInit.User::message
        IL_000a:  ret
      } // end of method User::.cctor
      • 實現顯式的靜態構造函數,例如上例中有靜態構造函數存在時,將首先執行靜態成員的初始化過程,再執行靜態構造函數初始化過程,.cctor的IL代碼實現為:
      .method private hidebysig specialname rtspecialname static 
              void  .cctor() cil managed
      {
        // Code size       23 (0x17)
        .maxstack  8
        IL_0000:  ldstr      "Initialize when defined."
        IL_0005:  stsfld     string Anytao.Write.TypeInit.User::message
        IL_000a:  nop
        IL_000b:  ldstr      "Initialize in static constructor."
        IL_0010:  stsfld     string Anytao.Write.TypeInit.User::message
        IL_0015:  nop
        IL_0016:  ret
      } // end of method User::.cctor

      同時,我們必須明確一些靜態構造函數的基本規則,包括:

      • 必須為靜態無參構造函數,并且一個類只能有一個。
      • 只能對靜態成員進行初始化。
      • 靜態無參構造函數可以和非靜態無參構造函數共存,區別在于二者的執行時間,詳見《你必須知道的.NET》7.8節 “動靜之間:靜態和非靜態”的論述,其他更多的區別和差異也詳見本節的描述。

      3 深入執行過程

      因為類型構造器本身的特點,在一定程度上決定了.cctor的調用時機并非是一個確定的概念。因為類型構造器都是private的,用戶不能顯式調用類型構造器。所以關于類型構造器的執行時機問題在.NET中主要包括兩種方案:

      • precise方式
      • beforefieldinit方式

      二者的執行差別主要體現在是否為類型實現了顯式的靜態構造函數,如果實現了顯式的靜態構造函數,則按照precise方式執行;如果沒有實現顯式的靜態構造函數,則按照beforefieldinit方式執行。
      為了說清楚類型構造器的執行情況,我們首先在概念上必須明確一個前提,那就是precise的語義明確了.cctor的調用和調用存取靜態成員的時機存在精確的關系,所以換句話說,類型構造器的執行時機在語義上決定于是否顯式的聲明了靜態構造函數,以及存取靜態成員的時機,這兩個因素。
      我們還是從User類的實現說起,一一過招分析這兩種方式的執行過程。
      3.1 precise方式
      首先實現顯式的靜態構造函數方案,為:

          // Release : code02, 2008/11/02                
          // Author  : Anytao, http://www.anytao.com 
          public class User
          {
              //Explicit Constructor
              static User()
              {
                  message = "Initialize in static constructor.";
              }
       
              public static string message = "Initialize when defined.";
          }

      對應的IL代碼為:

      .class public auto ansi User
          extends [mscorlib]System.Object
      {
          .method private hidebysig specialname rtspecialname static void .cctor() cil managed
          {
              .maxstack 8
              L_0000: ldstr "Initialize when defined."
              L_0005: stsfld string Anytao.Write.TypeInit.User::message
              L_000a: nop 
              L_000b: ldstr "Initialize in static constructor."
              L_0010: stsfld string Anytao.Write.TypeInit.User::message
              L_0015: nop 
              L_0016: ret 
          }
       
          .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
          {
              .maxstack 8
              L_0000: ldarg.0 
              L_0001: call instance void [mscorlib]System.Object::.ctor()
              L_0006: ret 
          }
       
          .field public static string message
      }

      為了進行對比分析,我們需要首先分析beforefieldinit方式的執行情況,所以接著繼續。。。
      3.2 beforefieldinit方式
      為User類型,不實現顯式的靜態構造函數方案,為:

          // Release : code03, 2008/11/02                
          // Author  : Anytao, http://www.anytao.com 
          public class User
          {
              //Implicit Constructor
              public static string message = "Initialize when defined.";
          }

      對應的IL代碼為:

      .class public auto ansi beforefieldinit User
          extends [mscorlib]System.Object
      {
          .method private hidebysig specialname rtspecialname static void .cctor() cil managed
          {
              .maxstack 8
              L_0000: ldstr "Initialize when defined."
              L_0005: stsfld string Anytao.Write.TypeInit.User::message
              L_000a: ret 
          }
       
          .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
          {
              .maxstack 8
              L_0000: ldarg.0 
              L_0001: call instance void [mscorlib]System.Object::.ctor()
              L_0006: ret 
          }
       
          .field public static string message
      }

      3.3 分析差別
      從IL代碼的執行過程而言,我們首先可以了解的是在顯式和隱式實現類型構造函數的內部,除了添加新的初始化操作之外,二者的實現是基本相同的。所以要找出兩種方式的差別,我們最終將著眼點鎖定在二者元數據的聲明上,隱式方式多了一個稱為beforefieldinit標記的指令。
      那么,beforefieldinit究竟表示什么樣的語義呢?Scott Allen對此進行了詳細的解釋:beforefieldinit為CLR提供了在任何時候執行.cctor的授權,只要該方法在第一次訪問類型的靜態字段之前執行即可。
      所以,如果對precise方式和beforefieldinit方式進行比較時,二者的差別就在于是否在元數據聲明時標記了beforefieldinit指令。precise方式下,CLR必須在第一次訪問該類型的靜態成員或者實例成員之前執行類型構造器,也就是說必須剛好在存取靜態成員或者創建實例成員之前完成類型構造器的調用;beforefieldinit方式下,CLR可以在任何時候執行類型構造器,一定程度上實現了對執行性能的優化,因此較precise方式更加高效。
      值得注意的是,當有多個beforefieldinit構造器存在時,CLR無法保證這多個構造器之間的執行順序,因此我們在實際的編碼時應該盡量避免這種情況的發生。

      4 回歸問題,必要的小結

      本文源于Artech兄的一個問題,希望通過上文的分析可以給出一點值得參考的背景?,F在就關于Type Initializer和 BeforeFieldInit的問題,看看大家能否給出正確的解釋一文中的幾個示例進行一些繼續的分析:

      • 在蔣兄的開始的示例實現中,可以很容易的來確定對于顯式實現了靜態構造函數的情況,類型構造器的調用在剛好引用靜態成員之前發生,所以不管是否在Main中聲明
      string field = Foo.Field;

      執行的結果不受影響。

      • 而在沒有顯式實現靜態構造函數的情況下,beforefieldinit優化了類型構造器的執行不在確定的時間執行,只要實在靜態成員引用或者類型實例發生之前即可,所以在Debug環境下調用的時機變得不按常理。然而在Release優化模式下,beforefieldinit的執行順序并不受
      string field = Foo.Field;

      的影響,完全符合beforefieldinit優化執行的語義定義。

      • 關于最后一個靜態成員繼承情況的結果,正像本文開始描述的邏輯一樣,類型構造器是在靜態成員被調用或者創建實例時發生,所以示例的結果是完全遵守規范的。不過,我并不建議子類最好不要調用父類靜態成員,原因是作為繼承機制而言,子承父業是繼承的基本規范,除了強制為private之外,所有的成員或者方法都應在子類中可見。而對于存在的潛在問題,更好的以規范來約束可能會更好。其中,靜態方法一定程度上是一種結構化的實現機制,在面向對象的繼承關系中,本質上就存在一定的不足。
      • 在c#規范中,關于beforefieldinit的控制已經引起很多的關注和非議,一方面beforefieldinit方式可以有效的優化調用性能,但是以顯式和或者隱式實現靜態構造函數的方式不能更有直觀的讓程序開發者來控制,因此在以后版本的c#中,能實現基于特性的聲明方式來控制,是值得期待的。
      • 另一方面,在有兩個類型的類型構造器相互引用的情況下,CLR無法保證類型構造器的調用順序,對程序開發者而言,我同樣強調了對于類型構造器而言,我們應該盡量避免要求順序相關的業務邏輯,因為很多時候執行的順序并非聲明的順序,這是值得關注的。

      5 結論

      除了補充Artech老兄的問題,本文算是繼續了關于類型構造器在《你必須知道的.NET》7.8節 “動靜之間:靜態和非靜態”中的探討,以更全面的視角來進一步闡釋這個問題。在最后,關于beforefieldinit標記引起的類型構造器調用優化的問題,雖然沒有完全100%的了解在Debug模式下的CLR調用行為,但是深入細節我們可以掌控對于語言之內更多的理解,從這點而言,本文是個開始。

       

      anytao | ? 2008 Anytao.com

      2008/11/02 | 榮譽出品:http://www.rzrgm.cn/anytao

      本文以“現狀”提供且沒有任何擔保,同時也沒有授予任何權利。 | This posting is provided "AS IS" with no warranties, and confers no rights.

      本文版權歸作者所有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。

       

      參考文獻

    3. 你必須知道的.NET》7.8節 “動靜之間:靜態和非靜態”
    4. Artech,關于Type Initializer和 BeforeFieldInit的問題,看看大家能否給出正確的解釋
    5. 通過七個關鍵編程技巧得益于靜態內容

      溫故知新

      [開篇有益]
      [第一回:恩怨情仇:is和as]
      [第二回:對抽象編程:接口和抽象類]
      [第三回:歷史糾葛:特性和屬性]
      [第四回:后來居上:class和struct]
      [第五回:深入淺出關鍵字---把new說透]
      [第六回:深入淺出關鍵字---base和this]
      [第七回:品味類型---從通用類型系統開始]
      [第八回:品味類型---值類型與引用類型(上)-內存有理]
      [第九回:品味類型---值類型與引用類型(中)-規則無邊]
      [第十回:品味類型---值類型與引用類型(下)-應用征途]
      [第十一回:參數之惑---傳遞的藝術(上)]
      [第十二回:參數之惑---傳遞的藝術(下)]
      [第十三回:從Hello, world開始認識IL]
      [第十四回:認識IL代碼---從開始到現在]
      [第十五回:繼承本質論]
      [第十六回:深入淺出關鍵字---using全接觸]
      [第十七回:貌合神離:覆寫和重載]
      [第十八回:對象創建始末(上)]
      [第十九回:對象創建始末(下)]
      [第二十回:學習方法論]
      [第二十一回:認識全面的null]
      [第二十二回:字符串駐留(上)---帶著問題思考]

    6. posted @ 2008-11-02 02:53  Anytao  閱讀(8677)  評論(57)    收藏  舉報
      主站蜘蛛池模板: 亚洲а∨天堂久久精品2021| 亚洲成人av在线高清| 国产剧情视频一区二区麻豆| 国产成人亚洲精品在线看| 爆乳女仆高潮在线观看| 国产成人高清精品免费软件| 国产av一区二区三区久久| 久久精品蜜芽亚洲国产AV| 亚洲欧美日韩人成在线播放| 国产精品成人午夜久久| 久久一日本道色综合久久| 麻豆蜜桃av蜜臀av色欲av| 亚洲色成人一区二区三区| 51妺嘿嘿午夜福利| 亚洲天堂男人影院| 人妻中文字幕亚洲精品| 久久国产成人午夜av影院| 高清在线一区二区三区视频| 国产欧美日韩亚洲一区二区三区| 日本边添边摸边做边爱的网站| 亚洲电影天堂av2017| 在线视频观看| 亚洲精品男男一区二区| 日本一级午夜福利免费区| 一区二区三区国产亚洲网站| 福利一区二区不卡国产| 亚洲精品第一区二区在线| 亚洲国产精品无码久久久| 色一伊人区二区亚洲最大| 亚洲综合久久精品哦夜夜嗨| 成人午夜av在线播放| 久久亚洲精品11p| 国产不卡在线一区二区| 99re6这里有精品热视频 | 四虎影视www在线播放| 国模粉嫩小泬视频在线观看| 亚洲欧美日本久久网站| 亚洲大尺度无码专区尤物| 欧美熟妇乱子伦XX视频| 色先锋av影音先锋在线 | 久久精品女人天堂av|