【问题标题】:Collection lookups; alternative to Dictionary集合查找;字典的替代品
【发布时间】:2010-11-06 10:12:09
【问题描述】:

TimeSheetActivity 类有一个分配集合。分配是一个值对象,也被域中的其他对象使用,看起来像这样:

public class Allocation : ValueObject
{
    public virtual StaffMember StaffMember { get; private set; }
    public virtual TimeSheetActivity Activity { get; private set; }
    public virtual DateTime EventDate { get ... }
    public virtual TimeQuantity TimeSpent { get ... }
}

不允许对同一个 Allocation.EventDate 进行重复分配。因此,当客户端尝试对活动进行分配时,会检查集合中是否已经存在同一个 Allocation.EventDate 的 Allocation。如果不是,则将新的 Allocation 添加到集合中,但如果是,则将现有的 Allocation 替换为新的。

我目前正在使用字典来维护集合,并以 Allocation.EventDate 作为键。它适用于域,但我想知道密钥已经是值的一部分这一事实本身是否不是“难闻的气味”。

除了字典值之外,我也没有理由保留任何内容。因为我使用的是 NHibernate,所以我可能需要编写一些自定义类型来做到这一点,我想知道这是否也是我应该使用不同类型的集合的线索。 (这也是 Allocation 类中的虚拟属性的原因)。

我正在考虑的主要替代方案是带有专用 EqualityComparer 的 HashSet。

你怎么看?

干杯, 浆果

【问题讨论】:

  • 我知道这是一个非常古老的问题。但我想知道为什么没有人建议使用链表,毕竟这是字典内部用于冲突哈希的内容。 Dictionary<TKey, TValue> 不能有重复键的唯一原因是当你查找一个时它不知道返回什么。 (顺便说一句,将链接类型设为结构,可以节省很多性能。)

标签: c# collections dictionary nhibernate-mapping hashset


【解决方案1】:

如果您使用外部比较器来执行HashSet<Allocation>,则必须非常小心,不要在不重新键入字典中的值的情况下更改日期。无论哪种方式,您都会遇到这个问题,但它会因可变性而加剧(至少对于Dictionary<,>,它仍然能够跟踪自己的键和值)。使用可变值作为键的一部分,您可能再也看不到该值...

当我过去在调度系统上工作时,我实际上为此使用了SortedList<,> - 类似,但如果您通常希望数据按顺序排列,并且如果数据相当统一则允许二进制搜索。

【讨论】:

  • 感谢有关 SortedList 的提示。干杯
【解决方案2】:

我不认为 key 是 value 的一部分这一事实一定是个问题。根据我的经验,字典经常出现这种情况。只要您永远不需要使用特定的EventDate 获取当前对象,带有适当相等比较器的HashSet 肯定会起作用。这似乎是一件很有用的事情,可能……

您目前是否只是有点模糊地担心,或者您对这可能会如何咬您有一个具体的怀疑?

【讨论】:

  • 我真的很想验证关于 key 是 value 一部分的有点模糊的担忧。说实话,这本词典很好用,而且很容易使用。我刚刚完成了你书的第 1 部分,顺便说一句……你是一位了不起的作家!
【解决方案3】:

使用标准库,我知道没有更好的解决方案。但是,我也觉得这种代码是一种“难闻的气味”,但这是因为 BCL 中的集合类而不是您的代码。

我不知道为什么 MS 没有创建通用 Sets<TKey, TData> where TData: IKeyed<TKey> 左右而不是字典,因为这将允许实现这样的数据结构,其中键是数据的一部分。 KeyValuePair<TKey, TValue>: IKeyed<TKey> 将只是一个实现此接口的辅助结构,因此允许创建与我们现在拥有的相同的字典功能。

另外(继续小吐槽)我想知道为什么他们没有添加声明性不可变类型的概念并使其成为可能的泛型类型约束,因为这样可以确保键在运行时不会更改其哈希码(如果在某个可变对象上实现GetHashCode()Equals(),目前可能会发生这种情况)。

【讨论】:

  • 使用可变类型的对象作为字典键没有任何问题,只要以这种方式使用的对象 instance 不会暴露给可能发生变异的代码它存储在字典中。让框架/编译器协助维护可变类型的不可变实例会很有帮助,但它需要对类型系统进行一些重大更改。
  • @supercat,很明显,如果可变对象被处理并用作不可变对象,那很好。我的意思是编译器无法帮助告诉您关键对象的任何突变都会破坏查找,即使您传入已用作键的相同对象,因为GetHashCode() 将使字典或哈希表看起来在错误的桶。有保障就好了。
猜你喜欢
  • 2012-08-30
  • 2011-07-29
  • 1970-01-01
  • 2018-06-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多