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

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

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

      C# 委托與 Lambda 表達式轉換機制及弱事件模式下的生命周期分析

      1. 委托內部結構

      委托類型包含三個重要的非公共字段:

      • _target 字段

        • 靜態方法包裝:當委托包裝一個靜態方法時,該字段為 null。
        • 實例方法包裝:當委托包裝實例方法時,該字段引用回調方法所操作的對象。
      • _methodPtr 字段

        • 標識委托要調用的方法。
      • _invocationList 字段

        • 存儲委托鏈(即內部委托數組),用于實現多播委托。

      2. Lambda 表達式轉換為委托實例

      C# 編譯器會將 lambda 表達式轉換成相應的委托實例,具體轉換方式依賴于 lambda 是否捕獲外部數據。

      2.1 不捕獲任何外部數據

      • 轉換方式

        • 將 lambda 表達式生成為私有的靜態函數(編譯器自動生成方法名)。
        • 同時生成一個委托類型的靜態字段用于緩存委托實例。
      • 委托實例創建與緩存

        • 當調用包含 lambda 的方法時,先檢查靜態字段是否為 null。
        • 若不為 null,則直接返回緩存的委托實例;若為 null,則創建新的委托實例,并賦值給靜態字段。
        • 這種方式確保委托實例只創建一次,被靜態字段引用后不會被回收。

      2.2 捕獲實例成員(通過 this 訪問)

      • 轉換方式

        • 將 lambda 表達式生成為私有的實例函數(編譯器自動生成方法名)。
      • 委托實例創建

        • 每次調用包含 lambda 的方法時,都會實時創建一個新的委托實例,包裝該實例函數。

      2.3 捕獲非實例成員(例如局部變量)

      • 轉換方式

        • 編譯器生成一個私有的輔助閉包類(通常命名為 “<>c__DisplayClassXXX”)。
        • 輔助類中包含公開字段,用于保存捕獲的局部變量(或其他非實例數據)。
        • 在該輔助類中,將 lambda 表達式轉換為公開的實例函數,該方法通過訪問輔助類字段來使用捕獲的數據。
      • 委托與閉包實例的創建

        • 每次調用包含 lambda 的方法時,都會生成一個輔助類實例。
        • 然后創建一個委托實例,其 _target 字段指向該輔助類實例。
        • 注意:在循環中容易產生閉包陷阱——盡管每次迭代可能創建多個輔助類實例與委托實例,但這些輔助類實例中的捕獲字段指向同一塊內存(即共享同一循環變量)。由于 lambda 表達式通常在循環結束后執行,所有回調看到的循環變量值往往都是最后一次迭代的狀態。
        • 另外,不同版本的 C# 對于循環中輔助類實例的創建可能存在差異,有的版本可能只在進入方法時創建一次,而有的版本則每次迭代都創建新的實例。至于委托實例,我猜測每次迭代都會創建一個新的委托實例(否則作為字典鍵時可能會出現重復的問題),但《CLR Via C# 第四版》中示例代碼(17.7.3節,中文版365頁)顯示委托實例只創建了一次,這里感覺有點問題,有興趣的朋友可以分析一下。

      3. 委托實例的訂閱與生命周期

      3.1 常規委托/事件訂閱

      • 當委托實例訂閱到常規委托或事件時,事件源對委托實例持有強引用,從而延長委托實例的生命周期(直至取消訂閱或事件源回收)。

      3.2 弱事件訂閱

      • 弱事件模式特點

        • 委托實例的生命周期至少大于其 _target 引用的對象的生命周期。
      • 實現機制

        • 利用 ConditionalWeakTable<TKey, TValue> 進行關聯:
          • 將 _target 引用的對象作為 key。
          • 將委托實例作為 value。
        • ConditionalWeakTable 對 key 使用弱引用,但對 value 使用強引用,保證只要 key 存在,對應的 value 就不會被回收。
      • 訂閱流程

        • 當委托實例通過 WeakEventManager<TEventSource, TEventArgs> 訂閱弱事件時,內部會通過 Delegate.Target 獲取 _target 引用的對象,并將該對象與委托實例關聯到 ConditionalWeakTable 中,從而確保委托實例的生命周期至少與 _target 對象一致。

      上面用工具重新排版了下,下面是我編輯的原文:

      委托類型包含三個重要的非公共字段:_target字段,當委托實例包裝一個靜態方法時,該字段為空;包裝實例方法時,這個字段引用回調方法要操作的對象。_methodPtr字段標識要回調的方法。_invocationList字段引用委托數組。

      C#編譯器將lambda方法替換為對應的委托實例。

      當lambda不獲取任何外部數據時,調用只創建一次委托實例并緩存:C#編譯器將lambda表達式生成為私有的靜態函數(編譯器自動取名的方法),并生成一個委托類型的靜態字段。當調用使用lambda的方法時,先判斷自動生成的靜態字段是否為空,不為空則直接返回靜態字段引用的委托實例,為空則先創建一個包裝靜態函數的委托實例賦值給靜態委托字段。(這導致被靜態字段引用的委托實例不會被釋放,但委托實例只會被創建一次)。

      當lambda獲取實例成員時(通過this指針訪問),每次調用都創建新的委托實例:C#編譯器將lambda表達式生成為私有的實例函數(編譯器自動取名的方法)。每次調用使用lambda的方法時都實時創建一個委托實例包裝該自動生成的實例函數。

      當lambda獲取非實例成員時(不通過當前實例的this指針訪問,比如局部變量),C#編譯器創建一個私有的輔助類,輔助類擁有對應的公開字段引用非實例成員,在輔助類中將將lambda表達式生成為公開的實例函數。每次調用使用lambda的方法時都生成輔助類實例,引用相同的非實例成員,然后創建委托實例傳入輔助類實例。(循環中的閉包陷阱就在于循環中雖然創建了多個輔助類實例與委托實例,但不同輔助類實例引用的非實例成員是同一塊內存。lambda 表達式是在循環中創建,但其執行往往是在循環結束后才發生,所以所有回調看到的循環變量都是最終狀態。并且不同版本C#實現在循環中可能并沒有創建循環次數的輔助類實例,而是在進入方法時只創建一次。我猜測創建了循環次數的委托實例,不然作為字典的鍵時就應該出錯了。但CLR Via C#第四版給的示例代碼中委托實例只創建了一次,這可能有點問題,有興趣的朋友可以分析一下。

      lambda被轉換為委托實例后,當將該委托實例訂閱到常規委托、事件時,事件源對委托實例進行強引用。

      當將該委托實例訂閱到弱事件時,存在有意思的現象:委托實例的生命周期最起碼大于_target引用的對象的生命周期。這是通過ConditionalWeakTable<TKey, TValue>實現的,通過將_target引用的對象設置為key、將委托實例設置為value。該類負責數據間的關聯,它對key是弱引用,但保證只要key在內存中,value就一定在內存中。

      委托實例通過WeakEventManager<TEventSource, TEventArgs>訂閱弱事件時,WeakEventManager<TEventSource, TEventArgs>內部會通過Delegate.Target拿到委托實例中_target引用的對象,作為ConditionalWeakTable的key,委托實例作為ConditionalWeakTable的value進行關聯。這樣就保證了弱事件模式下委托實例的生命周期至少大于_target引用的對象的生命周期。

      public void AddHandler(Delegate handler)
      {
          Invariant.Assert(_users == 0, "Cannot modify a ListenerList that is in use");
          object obj = handler.Target;
          if (obj == null)
          {
              obj = StaticSource;
          }
      
          _list.Add(new Listener(obj, handler));
          AddHandlerToCWT(obj, handler);
      }
      
      private void AddHandlerToCWT(object target, Delegate handler)
      {
          if (!_cwt.TryGetValue(target, out var value))
          {
              _cwt.Add(target, handler);
              return;
          }
      
          List<Delegate> list = value as List<Delegate>;
          if (list == null)
          {
              Delegate item = value as Delegate;
              list = new List<Delegate>();
              list.Add(item);
              _cwt.Remove(target);
              _cwt.Add(target, list);
          }
      
          list.Add(handler);
      }

       

      posted @ 2025-02-26 20:38  陳百川  閱讀(602)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 乱中年女人伦av二区| 午夜射精日本三级| 久久一夜天堂av一区二区| 亚洲高潮喷水无码AV电影| 欧美乱码精品一区二区三区| 精品精品亚洲高清a毛片| 狠狠综合久久av一区二| 国产萌白酱喷水视频在线观看| 国产毛片欧美毛片久久久| 国产精品国产三级国av| 国产精品一区二区色综合| 性少妇tubevⅰdeos高清| 虎林市| 久久国产精品不只是精品| 久久99精品久久99日本| 日韩欧美一卡2卡3卡4卡无卡免费2020 | 少妇粗大进出白浆嘿嘿视频| 囯产精品久久久久久久久久妞妞| 美乳丰满人妻无码视频| 亚洲日本中文字幕天天更新| 精品国产福利一区二区在线| 亚洲香蕉网久久综合影视| 中文字幕人成无码免费视频 | 荔浦县| 熟女国产精品一区二区三| 国产999精品2卡3卡4卡| 青草青草视频2免费观看| 18禁极品一区二区三区| 国产办公室秘书无码精品99| 亚洲最大中文字幕无码网站| 兔费看少妇性l交大片免费| 国产亚洲无线码一区二区| 亚洲成年av天堂动漫网站| 大尺度国产一区二区视频| 国产色婷婷亚洲99精品小说| 国产成人乱色伦区| 亚洲综合成人av在线| 乱人伦人妻中文字幕无码久久网| 精品一区二区三区四区五区| 欧美丰满熟妇xxxx性ppx人交| 自拍偷拍一区二区三区四|