簡體   English   中英

在將 TryGetValue 插入集合后,如何更新從 TryGetValue 返回的引用?

[英]How can I update a reference returned from TryGetValue after its been inserted into a collection?

我在字典里有一本字典。 在將內部字典添加到外部字典后,我想將對內部字典的引用設置為一個值:

var mammalIdSubscribers = new Dictionary<int, Dictionary<Guid, int>>();
        
var mammalId = 0;
if (!mammalIdSubscribers.TryGetValue(mammalId, out var mammalSubscribers))
    mammalIdSubscribers[mammalId] = mammalSubscribers; // Add reference to inner dict to outer dict
        
Subscribe(ref mammalSubscribers);

/* 
mammalIdSubscribers[mammalId] is still null after the call 
to Subscribe despite mammalSubscribers being non-null. Why?
*/
        
static void Subscribe(ref Dictionary<Guid, int> subscribers)
{
    subscribers = new Dictionary<Guid, int> { { Guid.NewGuid(), 10 } };
}

不幸的是,這不起作用,我不確定為什么( Console.WriteLine(mammalSubscribers.First().Value);拋出 null 引用異常)。

有人可以解釋為什么這不起作用嗎? 換句話說,為什么在使用ref關鍵字調用Subscribe之后, mammalIdSubscribers[0]仍然是null

您的變量mammalIdSubscribersmammalSubscribers的名稱非常相似,因此為了清楚起見,我將mammalIdSubscribers重命名為“ outerDict ”或“ biggerDict ”,而mammalSubscribers重命名為“ encarta ”,因為我經常將其用作參考作為一個 sprog。

逐行...

  1. var biggerDict = new Dictionary<int, Dictionary<Guid, int>>();
    • 這給了我們一個有效但空的biggerDict字典。
  2. var mammalId = 0;
    • 不言自明。
  3. biggerDict.TryGetValue(mammalId, out var encarta)
    • 這評估為false out參數也是一個內聯out聲明,當您將內聯out聲明與DictionaryTryGetValue一起使用時,新變量在返回false時將為null (或default )。
    • ...它會返回false ,因為biggerDict是空的,如前所述。
    • ...因此encartanull
    • (如果你眨眼錯過了它: encarta是堆棧上一個新的 GC 引用類型變量,它不是biggerDict任何部分的別名或“引用” )。
  4. 因為TryGetValue調用在if(.TryGetValue(...) )語句中,這意味着biggerDict[mammalId] = encarta; 將被評估。
    • encarta仍然是null
    • ...因此biggerDict[mammalId] (又名biggerDict[0] )是null
  • Subscribe(ref encarta);
    • 這會將對局部變量encarta的引用傳遞給Subscribe
    • 至關重要的是, encarta不是biggerDict中任何槽或空間的引用:它仍然只是一個堆棧分配(也稱為自動)對象引用大小的槽,它仍然是null
  1. encarta = new Dictionary<Guid, int> { { Guid.NewGuid(), 10 } };
    • Subscribe內部,在機器語言級別,指向堆棧分配的本地encarta的指針(-ish)被引用並分配給new Dictionary<Guid, int> { { Guid.NewGuid(), 10 } }; .
    • ...這意味着encarta現在不是null
    • 然后執行返回到之前的function。
  2. encarta local 現在是對 GC 堆上有效字典 object 的引用。 但是沒有任何東西調用biggerDict[int].set_Item屬性設置器來使biggerDict[0]成為非null引用encarta指向的同一個 object
  3. 請記住,除了真正的arrays ( T[] ),所有其他帶有索引器的類型都只是屬性 getter/setter 方法的糖分, 這意味着 object 引用是按值傳遞的,而不是按引用傳遞的引用——至少不是沒有一個ref返回屬性, Dictionary<K,V>沒有。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM