C# 使用两个字段的组合作为字典中的键

C# 使用两个字段的组合作为字典中的键,c#,dictionary,hash,C#,Dictionary,Hash,我需要存储一个c#dict,在这里我可以存储基于IntPtr和enum的成员(如果有帮助的话,可以转换为int)。换句话说,如果我得到相同的IntPtr和enum匹配(命名为sp_playlist_type),我需要能够得到相同的结果,但只有这样(这也很重要)。我想我应该创建一个包含这两个数字的结构,并重写GetHashCode(),但是我需要一个哈希算法,它不会为这两个数字创建重复项,并且每次出现相同的两个数字时都会生成相同的结果 然后我需要一个哈希算法,它不会为这两个数字创建重复项 事实并非

我需要存储一个c#dict,在这里我可以存储基于IntPtr和enum的成员(如果有帮助的话,可以转换为int)。换句话说,如果我得到相同的IntPtr和enum匹配(命名为sp_playlist_type),我需要能够得到相同的结果,但只有这样(这也很重要)。我想我应该创建一个包含这两个数字的结构,并重写GetHashCode(),但是我需要一个哈希算法,它不会为这两个数字创建重复项,并且每次出现相同的两个数字时都会生成相同的结果

然后我需要一个哈希算法,它不会为这两个数字创建重复项

事实并非如此。您需要重写
GetHashCode()
,但它可能会发生冲突。您希望最小化哈希代码中的冲突,而不是消除它们


这实际上相当容易做到。一个常见的选择是只使用结构的两个成员的哈希代码的异或,或者类似的东西。

我认为基于元组的GetHashCode和相等的创建方式,您可以:

Dictionary<Tuple<IntPtr, YourEnum>, YourResultType>
字典

当然,如果您使用的是.NET 4.0。

一种简单的方法是使用字符串作为键,您可以在该字符串中组合这两个值。例如:

private string GetKey(IntPrt prt, sp_playlist_type playlist_type)
{
    return string.format("{0}#{1}", prt, type)
}
要使用它,您可以使用以下内容:

mydic.add(GetKey(ptr, playlist_type), myvalue);

完全没有必要重写GetHashCode,因为正如其他人提到的,不要求它是唯一的

但是,出于性能原因,可能需要为结构重写Equals


在这种情况下是这样的。在这种情况下,可能是IntPtr和enum(64位系统上IntPtr的LS 32位)的异或。

Reed,如果我错了,请纠正我,但我认为Tuple类重写GetHashCode是成员散列码的组合(对于eqality也是如此)。难道我们就不能拥有:Dictionary吗?@James:Tuple如果不想编写自定义结构就可以了。我经常会写我自己的结构,特别是如果它将被大量使用,因为它更清晰-但元组可以很好地工作。是的,非常正确。我反复讨论我是喜欢元组还是自定义结构。对于
enum
s,简单异或并不是一个非常明智的选择,因为它可以接受很少的值;只有低阶位不同,可能会减慢哈希表的探测速度。标准错误。散列只需要复制相同的数字,它不必是唯一的。Equals()负责标识。@Hans:Equals是否从
字典
调用?如前所述,哈希代码不必是唯一的。但是,两个相等的对象必须具有彼此相同的哈希代码。Playlist表明它不是一个大列表,但它不是一个高性能的解决方案,是吗?由于字符串转换,这将很快变得很慢。它也不是最好的散列。创建散列代码并确保正确分发是一种常见的模式。通过这种方式,您不需要创建新的结构或类并重写GetHashCode方法来将其用作键。它在所有框架版本中都有效。您可以在内部使用XOR而不是string.format。其思想是使用该方法,而不是创建新的类或结构,并重写GetHashCode。如果您使用的是4.0,那么使用Tuple是最好的选择如果您覆盖Equals,那么您必须覆盖GetHashCode。如果您的意思是强烈建议使用它,那么我同意-这就是我试图表达的观点。但是框架并不要求你这样做,如果你创建了一个等同于结构默认值的Equals实现,你就可以不这样做了。我的意思是,如果你不这样做,你就不能保证在字典中正确访问它。(也就是说,您的代码将存在严重缺陷。)对于您关于创建等效实现的观点,我想说,在这种情况下,您并没有真正覆盖Equals。