对象作为字典中的键

时间:2011-01-17 02:02:59

标签: c# asp.net dictionary c#-3.0 c#-2.0

我有这堂课:

class A {
    string name;
    string code;
}

示例:

A1: name="blabla", code="kuku"
A2: name="blabla", code=null
A3: name=null, code="kuku"

Dictionary<A, string> d=new Dictionary<A, string>();

d[A1]="aaa";
d[A2]="bbb"
results: d[A1]="bbb";

d[A1]="aaa";
d[A3]="bbb"
results: d[A1]="bbb";

d[A2]="aaa";
d[A3]="bbb"
results: d[A2]="aaa"; d[A3]="bbb";

有没有办法将A类实现为字典的键?

3 个答案:

答案 0 :(得分:3)

你不能。

Equals / GetHashCode实现必须形成[等价关系] - 它们必须满足以下属性:

  • a == a。 (自反)
  • 如果a == b则b == a。 (对称)
  • 如果a == b且b == c则a == c。 (及物)

您的定义不具有传递性; (a, b) == (b, c)(b, c) == (c, d)(a, b)!= (c, d)

答案 1 :(得分:3)

不是实现GetHashCode,更好的选择是实现自己的IEqualityComparer<A>并将其传递给字典的构造函数。话虽这么说,你的等价规则没有意义。编程中的等价性必须遵循标准的代数等价规则。

在您的情况下,您有三个被视为“相等”的对象,这似乎是基于两个属性中的一个是否相等。但是,这种方法不能提供所需的传递平等。由于名称,#1 =#2。因为代码,#1 =#3。但是,等式和等价要求如果a = b且b = c,则a = c。在您的情况下,将#2与#3进行比较显示没有等价或相等,因为它们没有匹配的属性,即使它们都等于#1。

简短版本是您的等同/等效规则不能用于任何基于密钥的存储库,例如Dictionary

如果您确信这是正确的方法,那么这将是您正在寻找的,,但这不会表现得一致。使用这种伪等价,没有什么能够始终如一。

class AEqualityComparer : IEqualityComparer<A>
{
    public bool Equals(A x, A y)
    {
        return x == y || x.name == y.name || x.code == y.code;
    }

    public int GetHashCode(A x)
    {
        return -1; // impossible to compute; will negatively impact performance
    }
}

...

Dictionary<A, string> dict = new Dictionary<A, string>(new AEqualityComparer());

然而,打破这个很容易:

dict[A1] = "foo";
dict[A2] = "bar";

// dict[A1] is now "bar", as expected

dict[A3] = "baz";

此处,dict[A1]"baz",正如所料。但是,dict[A2] 也是 "baz",即使A2根据这些规则不等于A3。这是因为使用的原始对象是A1,它等于两者。

答案 2 :(得分:1)

回答您编辑过的问题:

制作两个不同的字典词典(一个用于名称,一个用于代码),并搜索您有值的字典。