Cor*_*ker 5 .net c# dictionary hashtable
我有一个Dictionary<Guid, ElementViewModel>.(ElementViewModel是我们自己的复杂类型.)我使用股票标准将项目添加到字典中items.Add(Guid.NewGuid, new ElementViewModel() { /*setters go here*/ });,
稍后我会删除部分或全部这些项目.
我的ElementViewModel的简单视图是这样的:
class ElementViewModel
{
Guid Id { get; set; }
string Name { get; set; }
int SequenceNo { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
值得一提的是,如果发生移动和复制等其他操作,则在添加后,SequenceNos在集合中被压缩.{1,5,6} - > {1,2,3}
我的删除操作的简单视图是:
public void RemoveElementViewModel(IEnumerable<ElementViewModel> elementsToDelete)
{
foreach (var elementViewModel in elementsToDelete)
items.Remove(elementViewModel.Id);
CompactSequenceNumbers();
}
Run Code Online (Sandbox Code Playgroud)
我将用一个例子说明问题:
我在字典中添加了3个项目:
var newGuid = Guid.NewGuid();
items.Add(newGuid, new MineLayoutElementViewModel { Id = newGuid, SequenceNo = 1, Name = "Element 1" });
newGuid = Guid.NewGuid();
items.Add(newGuid, new MineLayoutElementViewModel { Id = newGuid, SequenceNo = 2, Name = "Element 2" });
newGuid = Guid.NewGuid();
items.Add(newGuid, new MineLayoutElementViewModel { Id = newGuid, SequenceNo = 3, Name = "Element 3" });
Run Code Online (Sandbox Code Playgroud)
我删除了2个项目
RemoveElementViewModel(new List<ElementViewModel> { item2, item3 }); //imagine I had them cached somewhere.
Run Code Online (Sandbox Code Playgroud)
现在我想添加2个其他项目:
newGuid = Guid.NewGuid();
items.Add(newGuid, new MineLayoutElementViewModel { Id = newGuid, SequenceNo = 2, Name = "Element 2, Part 2" });
newGuid = Guid.NewGuid();
items.Add(newGuid, new MineLayoutElementViewModel { Id = newGuid, SequenceNo = 3, Name = "Element 3, Part 2" });
Run Code Online (Sandbox Code Playgroud)
关于此时字典的评估,我预计项目的顺序为"元素1","元素2,第2部分","元素3,第2部分"
但它实际上按以下顺序排列:"元素1","元素3,第2部分","元素2,第2部分"
我依靠这些项目的顺序是某种方式.为什么不如预期,我能做些什么呢?
SLa*_*aks 14
.Net词典在设计上是无序的.
你应该用一个KeyedCollection<TKey, TValue>代替; 它将保留项目添加到集合的顺序,并且还将使用哈希表进行快速查找.
例如:
class ElementViewModelCollection : KeyedCollection<Guid, ElementViewModel> {
protected override Guid GetKeyForItem(ElementViewModel item) { return item.Id; }
}
items.Add(new MineLayoutElementViewModel { Id = Guid.NewGuid(), SequenceNo = 3, Name = "Element 3" });
Run Code Online (Sandbox Code Playgroud)
请注意,如果Id在将项添加到集合后更改属性,则需要ChangeItemKey在集合上调用该方法.我强烈建议您将该Id属性设置为只读.
不幸的是,SortedDictionary 对于我们必须存储在其中的大量数据而言不够快,并且 KeyedCollection 达不到手动压缩元素的 SequenceNo 属性的目的。
严格来说,我们应该重写排序发生的方式,因为我的解决方案不是最漂亮的:
每次删除项目时,都会新建字典并将未删除的项目重新添加到新字典中,以保持默认顺序。--> 我承认这是可怕的做法。计划在压力减轻后立即更改。