键值取决于值的键值对的集合

时间:2017-10-04 07:05:19

标签: c# dictionary key-value

我有一个班级MyClass

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

我想在集合中存储多个实例。我经常需要检查是否存在具有特定名称的实例,如果存在,则检索该实例。由于迭代整个集合不是一个选项(性能!),我想到了使用一组键值对,例如IDictionary<string, MyClass>

我的程序还允许重命名MyClass的实例(如果违反名称唯一性,则不允许重命名)。但是,如果我重命名MyClass,我还需要从字典中删除旧条目并添加新条目(即使用新名称)以保持数据一致。

问题在于我将在整个地方有几个这样的词典(其中包含所有MyClass个实例的子集),并且很难跟踪它们并在每次重命名后不断更新所有词典。

有没有办法让键值对自动保持一致?我想我听说过一个允许这个的数据结构,它至少存在于C ++中(不幸的是,我不知道它是如何被调用的)。基本上,它应该是一个集合,其中键不仅仅是一个普通字符串,而更像是对字符串的引用(在本例中为name属性),但行为就好像它是一个字符串。 C#中是否存在这样的事情?您是否有其他想法如何保持收藏一致?

我唯一的想法是在我的程序的最高级别上拥有所有词典的集合,并使重命名方法在实际重命名过程之后更新所有这些词典。但必须有更好的方法!

为什么这个问题不是Best way to change dictionary key的重复:

我已经知道字典不允许更改密钥。我反而要求另一个与键更改兼容的数据结构(不会完全失去性能优势),我也要求其他方法。因此,只要有助于解决保持数据一致的问题,我的问题就更容易从任何方向输入。

2 个答案:

答案 0 :(得分:2)

据我了解,您的问题是:

  • 您有多个词典,每个词典都包含部分数据
  • 所有实例在所有词典中都应具有唯一名称
  • 更改名称时:
    • 首先,检查此名称是否仍然是唯一的
    • 以其所存在的字典更新

我想我会稍微解决这个问题。

首先,将ID字段添加到将成为Guid /运行编号的类中。该字段永远不会从创建实例的那一刻起改变。
接下来,添加另一个仅包含 实例的名称和ID的字典,它应该如下所示:

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

其他词典会将ID作为键,而不是名称:

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

现在,当您更改实例的名称时,所有名称都存在于单个字典中,该字典将告诉您它是否已存在。而且你只需要在一个地方改变它,因为其余的词典依赖于一个永远不变的恒定值。
所以说你要更改"FirstName"的名称,名称字典将如下所示:

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

其余数据无需更改。

答案 1 :(得分: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);
        }
    }

我只写了非常基本的东西,你错过了所有的访问者和调查员,只需添加你需要的那些。

在枚举过程中要非常小心,因为在枚举期间更改集合会导致失败(并且由于隐藏了集合,您可能会在不知情的情况下执行此操作)