我有一个班级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的重复:
我已经知道字典不允许更改密钥。我反而要求另一个与键更改兼容的数据结构(不会完全失去性能优势),我也要求其他方法。因此,只要有助于解决保持数据一致的问题,我的问题就更容易从任何方向输入。
答案 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);
}
}
我只写了非常基本的东西,你错过了所有的访问者和调查员,只需添加你需要的那些。
在枚举过程中要非常小心,因为在枚举期间更改集合会导致失败(并且由于隐藏了集合,您可能会在不知情的情况下执行此操作)