C# 键依赖于值的键值对的集合

C# 键依赖于值的键值对的集合,c#,dictionary,key-value,C#,Dictionary,Key Value,我有一个班级MyClass class MyClass { public string Name { get; set; } // is unique among all instances public SomeClass Data { get; set; } ... } 我想在一个集合中存储几个实例。我经常需要检查是否存在具有特定名称的实例,如果存在,则检索该实例。由于遍历整个集合不是一个选项(性能!),因此我考虑使用键值对集合,例如IDictionary 我的程序

我有一个班级
MyClass

class MyClass
{
    public string Name { get; set; } // is unique among all instances
    public SomeClass Data { get; set; }
    ...
}
我想在一个集合中存储几个实例。我经常需要检查是否存在具有特定名称的实例,如果存在,则检索该实例。由于遍历整个集合不是一个选项(性能!),因此我考虑使用键值对集合,例如
IDictionary

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

问题是,我将有几个这样的字典(其中包含所有
MyClass
实例的子集)遍布各地,而且很难跟踪它们并在每次重命名后一致地更新所有字典

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

我唯一的想法是在程序的最高级别上收集所有字典,并使重命名方法在实际重命名过程之后更新所有这些字典。但一定有更好的办法


为什么这个问题不是重复的:


我已经知道字典不允许更改密钥。相反,我要求的是另一种数据结构,它以某种方式与关键更改兼容(而不会完全失去性能优势),我还要求采用其他方法。因此,我的问题对来自任何方向的输入都更加开放,只要它有助于解决保持数据一致性的问题。

我认为没有本地集合可以做到这一点。但是,只需在基类中添加某种通知,就可以轻松创建自己的通知

   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);
        }
    }
公共类ChangingNameObject
{
公共委托void ObjectNameChange(字符串oldName、字符串newName);
公共事件ObjectNameChange ObjectNameChanged;
私有字符串名称;
公共字符串名
{ 
get=>name;
设置
{
ObjectNameChanged?.Invoke(名称、值);
名称=值;
}
}
}
公共类监视词典
{
私有词典内容=新词典();
公共作废添加(更改名称对象项)
{
item.ObjectNameChanged+=UpdatePosition;
内容[项目名称]=项目;
}
公共作废删除(更改名称对象项)
{
item.ObjectNameChanged-=UpdatePosition;
内容。删除(项。名称);
}
私有void UpdatePosition(字符串oldname、字符串newname)
{
var o=内容[旧名称];
内容。删除(旧名称);
内容。添加(新名称,o);
}
}
我只写了一些非常基本的东西,但是你错过了所有的访问器和枚举器,只需添加你需要的


尽管在枚举过程中更改集合会导致失败(而且由于集合是隐藏的,您可能会在不知情的情况下执行此操作),但要非常小心枚举。

据我所知,您的问题是:

  • 您有多个字典,每个字典都保存一部分数据
  • 所有实例在所有字典中都应该有一个唯一的名称
  • 更改名称时:
    • 首先,检查此名称是否仍然唯一
    • 在它所在的dictionray中更新它
我想我会用不同的方式来解决这个问题

首先,向类中添加一个ID字段,该字段将是Guid/运行编号,该字段从创建实例的那一刻起就不应更改。
接下来,添加另一个只包含实例名称和ID的字典,它应该如下所示:

[{"FirstName": "Guid1"},   
{"SecondName": "Guid2"},   
{"ThirdName": "Guid3"}]  
[{"OtherName": "Guid1"},   
{"SecondName": "Guid2"},   
{"ThirdName": "Guid3"}] 
其余词典将以ID作为键,而不是名称:

[{"Guid1": {instance1}},  
{"Guid2": {instance2}}] 
现在,当您更改实例的名称时,所有名称都存在于一个字典中,该字典将告诉您实例是否已经存在。您只需要在单个位置更改它,因为其他字典依赖于一个永远不会更改的常量值。
因此,如果要更改
“FirstName”
的名称,名称词典将如下所示:

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

其余数据不需要更改。

使用字典(或任何其他键值集合)时,应确保键保持不变。这些集合之所以快速,是因为它们使用散列键,因此可以很快找到多个键。如果您修改了哈希函数中使用的值,您就完全失去了哈希功能,因此性能测试人员gainI不认为该问题是如上所述的重复问题,并会建议回答(与重复链接所指的答案不兼容)再次提问,我会回答,我投票赞成你的问题,但无法找到任何方式通知重新开放。是否有任何指定链接?很抱歉,我没有足够的分数来重新打开我自己抽象类
KeyedCollection
可能是实现这一点的好框架。