2017-10-04 53 views
5

我有一個類MyClass收集鍵 - 值對,其中關鍵取決於值

class MyClass 
{ 
    public string Name { get; set; } // is unique among all instances 
    public SomeClass Data { get; set; } 
    ... 
} 

其中我想幾個實例存儲收藏。我經常需要檢查是否存在具有某個名稱的實例,如果存在,請檢索該實例。由於遍歷整個集合不是一個選項(performance!),所以我想到了使用一組鍵值對,例如,一個IDictionary<string, MyClass>

我的程序還允許重命名MyClass的實例(如果名稱唯一性被違反,它將不允許重命名)。但是,如果我重命名MyClass,我還需要從字典中刪除舊條目並添加新條目(即使用新名稱)以保持數據的一致性。

問題在於,我將有幾個這樣的字典(其中包含所有MyClass實例的子集),並且在每次重命名後很難跟蹤它們並持續更新所有字典。

有沒有辦法讓鍵值對自動保持一致?我想我聽說過一個允許這樣的數據結構,至少在C++中存在(不幸的是,我不知道它是如何調用的)。基本上,它應該是一個集合,其中鍵不僅僅是一個純字符串,而更像是對字符串的引用(在這種情況下是名稱屬性),但其行爲就像它是一個字符串一樣。 C#中存在這樣的事情嗎?你有其他想法如何保持集合一致嗎?

我唯一的想法是在我的程序的最高級別上擁有所有字典的集合,並使重命名方法在實際重命名過程後更新所有這些字典。但是一定有更好的辦法!


爲什麼這個問題不是Best way to change dictionary key重複:

我已經知道,字典不允許改變的關鍵。相反,我要求另一個數據結構,它在某種程度上與關鍵更改兼容(不會完全喪失性能優勢),而且我也在尋求其他方法。所以我的問題是更加開放的從任何方向的輸入,只要它有助於解決保持數據一致的問題。

+1

使用字典(或任何其他鍵值集合)時,應確保密鑰保持不變。這些集合的速度很快的原因是它們使用散列鍵,因此可以非常快速地找到多個鍵。如果修改散列函數中使用的值,那麼您完全失去了散列函數,因此性能增益 – HimBromBeere

+0

我不認爲問題如上所述是重複的,並且會提示一個答案(其中與重複鏈接指向的答案不兼容) –

+0

再次詢問,我會回答 –

回答

2

據我瞭解你,你的問題是這樣的:

  • 你有多個詞典,每個握着你的數據的一部分。當一個名稱被更改
  • 所有實例應該有一個唯一的名稱在所有的字典
    • 首先,檢查這個名字,仍然是獨一無二
    • 更新它在任何dictionray它生活在

我想我會不同的解決這個問題有點。

首先,將一個ID字段添加到將成爲Guid /運行編號的類中,該字段應該從創建實例的那一刻起永遠不會改變。
接下來,添加另一個字典,將舉行實例的名稱和ID,它應該是這個樣子:

[{"FirstName": "Guid1"}, 
{"SecondName": "Guid2"}, 
{"ThirdName": "Guid3"}] 

你的字典的其餘部分將持有的ID作爲關鍵,而不是名稱:

[{"Guid1": {instance1}}, 
{"Guid2": {instance2}}] 

現在,當你改變實例的名稱,所有的名字在一個字典,會告訴你,如果它已經存在存在。而且你只需要在一個地方改變它,因爲其餘的字典依賴於永遠不會改變的恆定值。
所以說你想改變的"FirstName"名稱,名稱詞典將是這樣的:

[{"OtherName": "Guid1"}, 
{"SecondName": "Guid2"}, 
{"ThirdName": "Guid3"}] 

而其餘數據並不需要改變。

1

我不認爲有一個本地收集來做到這一點。不過,只需在基類中添加某種通知即可輕鬆創建自己的通知。

public class ChangingNameObject 
    { 
     public delegate void ObjectNameChange(string oldName, string newName); 
     public event ObjectNameChange ObjectNameChanged; 
     private string name; 
     public string Name 
     { 
      get => name; 
      set 
      { 
       ObjectNameChanged?.Invoke(name, value); 
       name = value; 
      } 
     } 
    } 

    public class WatchingDictionary 
    { 
     private Dictionary<string, ChangingNameObject> content = new Dictionary<string, ChangingNameObject>(); 

     public void Add(ChangingNameObject item) 
     { 
      item.ObjectNameChanged += UpdatePosition; 
      content[item.Name] = item; 
     } 

     public void Remove(ChangingNameObject item) 
     { 
      item.ObjectNameChanged -= UpdatePosition; 
      content.Remove(item.Name); 
     } 

     private void UpdatePosition(string oldname, string newname) 
     { 
      var o = content[oldname]; 
      content.Remove(oldname); 
      content.Add(newname, o); 
     } 
    } 

我只寫了非常基本的東西,你想念所有訪問器和枚舉器,只需添加一個你需要的。

要非常小心用枚舉雖然作爲枚舉過程中不斷變化的集合將導致一個失敗(和收集是隱藏的,youu可能不知道那樣做)

+1

抽象類「KeyedCollection 」可能是實現這一點的好框架。 – Kjara

+0

是的好點。我不知道這一個。 –