<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          我大意了,沒(méi)有閃。

          共 5059字,需瀏覽 11分鐘

           ·

          2023-08-22 19:47

                 本文的誕生,是有感于一線碼農(nóng)大佬前幾日公眾號(hào)發(fā)文《Dictionary.Clear 和 new Dictionary() 有什么不同?》,里面有兩個(gè)栗子讓我虎軀一震。


          1. 無(wú)心插花

          void Example1()
          {
            var newDict = new Dictionary<string, string>();
            newDict.Add("key1", "value1");
            newDict.Add("key2", "value2");
            foreach (var item in newDict)
            {
              newDict = new Dictionary<string, string>();  // 這里重新賦值
              Console.WriteLine($"new : {item}");
            }
          }

          void  Example2() 
          {
              var newDict= new Dictionary<string, string>();
              newDict.Add("key1", "value1");
              newDict.Add("key2", "value2");
              foreach (var item in newDict)
              {
                  newDict.Clear();       // 這里修改了原引用的數(shù)據(jù),為啥不報(bào)錯(cuò)?
                  Console.WriteLine($"clear : {item}");
              }
          }

          這兩個(gè)栗子輸出的是:

          new : [key1, value1]
          new : [key2, value2]
          clear : [key1, value1]

          這個(gè)輸出是不是很奇怪:

          (1) 栗子1重新new賦值難道不是修改了原字典對(duì)象newDict嗎?foreach字典為什么不報(bào)InvalidOperation異常?

          (2) 栗子2都肉眼可見(jiàn)的Clear字典了,foreach字典為什么還不報(bào)InvalidOperation異常?

          2. Example1:抓的是周樹(shù)人,與我魯迅何干?

          這個(gè)問(wèn)題我大意了,沒(méi)有閃????。

          這個(gè)問(wèn)題其實(shí)與foreach沒(méi)深入關(guān)系,其實(shí)就是多引用指向同一區(qū)域的問(wèn)題,還是說(shuō)下流程吧。

          (1) 對(duì)字典做foreach, 內(nèi)部會(huì)利用原對(duì)象newDict產(chǎn)生一個(gè)Enumerator迭代器。 IDictionaryEnumerator IDictionary.GetEnumerator() => new Enumerator(this, Enumerator.DictEntry);

          https://github.com/dotnet/runtime/blob/45acd380b37c9ee883070a70a2ef2cb7eca77683/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Dictionary.cs#L1331

          有關(guān)foreach本質(zhì),強(qiáng)烈推薦看這個(gè):2021年了,IEnumeratorIEnumerable還傻傻分不清楚?[1]

          (2) 關(guān)鍵是迭代器使用的新的readonly Dictionary<TKey, TValue> _dictionary;字段指向了原newDict指向的對(duì)象。

          https://github.com/dotnet/runtime/blob/45acd380b37c9ee883070a70a2ef2cb7eca77683/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Dictionary.cs#L1367

          (3) 于是在外部嘗試重置newDict,與_dictionary無(wú)關(guān),故會(huì)出現(xiàn)上面看似詭異的效果。

          抓的是周樹(shù)人,與我魯迅何干。


          3. Example2:.Net Core3.0+ breakChange

          Example2肉眼可見(jiàn)地在foreach內(nèi)變更了原迭代對(duì)象,竟然不報(bào)InvalidOperationException

          這個(gè)問(wèn)題說(shuō)來(lái)話長(zhǎng),真的說(shuō)來(lái)話長(zhǎng)。????

          循著源碼看迭代器報(bào)InvalidOperationException異常的時(shí)機(jī)、查看字典Clear方法:

          // https://github.com/dotnet/runtime/blob/64243bbf5e9ee53c0c4c5678f2cd8c7f1c9b4f6f/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Dictionary.cs#L1385
          if (_version != _dictionary._version)
          {
               ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumFailedVersion();
          }
            
          // https://github.com/dotnet/runtime/blob/cf258a14b70ad9069470a108f13765e0e5988f51/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Dictionary.cs#L223C5-L238C10
          public void Clear()
          {
              int count = _count;
              if (count > 0)
              {
                  Debug.Assert(_buckets != null, "_buckets should be non-null");
                  Debug.Assert(_entries != null, "_entries should be non-null");

                  Array.Clear(_buckets, 0, _buckets.Length);

                  _count = 0;
                  _freeList = -1;
                  _freeCount = 0;
                  Array.Clear(_entries, 0, count);
               }
          }

          靜態(tài)分析源碼,貌似Dictionary認(rèn)定字典正在變更的關(guān)鍵是verison字段發(fā)生變化Clear()字典清空了原鍵值對(duì)、count、空閑空間等字段,確實(shí)沒(méi)引起version字段變化。

          圍觀微軟官方Dictionary信源[2]

          屬性 Count 設(shè)置為 0,并且也會(huì)釋放對(duì)集合元素中其他對(duì)象的引用。容量保持不變。

          此方法是 O (n) 操作,其中 n 是字典的容量。

          僅限 .NET Core 3.0+ :可以安全地調(diào)用此可變方法,而不會(huì)使實(shí)例上的 Dictionary<TKey,TValue> 活動(dòng)枚舉器失效。這并不表示線程安全。


          技能點(diǎn):食之無(wú)用棄之可惜

          ok, That'all, 這是看一線碼農(nóng)大佬昨日分享《DictionaryClear和newDictionary有什么不同[3]》的一點(diǎn)補(bǔ)充,[把原文給出的字典Example改成List Example]那又是一個(gè)有意思的話題,暫時(shí)不表,讀者自行嘗試。

          本文沒(méi)啥有用技能點(diǎn),????

          一個(gè)是多引用指向同一片空間,另一個(gè)是源碼邏輯的breakChange,不成體系,食之無(wú)用棄之可惜。

          預(yù)告:今日既然聊到了C#字典,字典也是必考八股文,我會(huì)抽時(shí)間溫習(xí)C# Dictionary的實(shí)現(xiàn)并給出自己的理解。

          最后啰嗦一句:全文原創(chuàng),希望得到各位反饋,歡迎斧正交流, 若有更多進(jìn)展,會(huì)實(shí)時(shí)更新到[左下角閱讀原文]。

          引用鏈接

          [1] 2021年了,`IEnumerator`、`IEnumerable`還傻傻分不清楚?: https://www.cnblogs.com/JulianHuang/p/14271285.html

          [2] 微軟官方Dictionary信源: https://learn.microsoft.com/zh-cn/dotnet/api/system.collections.generic.dictionary-2.clear?view=net-7.0#system-collections-generic-dictionary-2-clear

          [3] Dictionary Clear和new Dictionary有什么不同: https://mp.weixin.qq.com/s/JUtr9TFRDfAvEeu6vJkI1w

          成文耗時(shí)4小時(shí),閱讀5min,有用指數(shù)拉胯。

          瀏覽 301
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  无码区一区二区 | 肏久久 | 亚洲清色 | 青草天堂 | 1级毛片特黄色 |