对象作为字典中的键

发布于 2024-10-12 22:46:44 字数 462 浏览 6 评论 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 类实现为字典的键?

I have this class:

class A {
    string name;
    string code;
}

Examples:

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";

Is there a way to implement class A as a Key to dictionary?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

画尸师 2024-10-19 22:46:44

你不能。

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

  • a == a。 (自反性)
  • 如果 a == b 则 b == a。 (对称性)
  • 如果 a == b 且 b == c,则 a == c。 (传递性)

你的定义是不传递的; (a, b) == (b, c)(b, c) == (c, d)< /code> 但(a, b) != (c, d)

You can't.

Equals / GetHashCode implementations must form an [equivalence relation] - they must satisfy the following properties:

  • a == a. (Reflexivity)
  • if a == b then b == a. (Symmetry)
  • if a == b and b == c then a == c. (Transitivity)

Your definition is not transitive; (a, b) == (b, c) and (b, c) == (c, d) but (a, b) != (c, d).

姜生凉生 2024-10-19 22:46:44

更好的选择是实现您自己的 IEqualityComparer 并将其传递给字典的构造函数,而不是实现 GetHashCode。话虽如此,您的等效规则没有意义。编程中的等价必须遵循标准代数等价规则。

在您的情况下,您有三个被视为“相等”的对象,这似乎基于两个属性之一是否相等。然而,这种方法没有提供必需的传递相等性。 #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,它等于两者。

Rather than implementing GetHashCode, a better option would be to implement your own IEqualityComparer<A> and pass that to the constructor for your dictionary. That being said, your rules for equivalence don't make sense. Equivalence in programming must follow standard algebraic equivalence rules.

In your case, you have three objects that are considered "equal", which seems to be based on whether or not one of two properties is equal. However, this approach doesn't provide for transitive equality, which is required. #1=#2 because of the name. #1=#3 because of the code. However, equality and equivalence requires that if a=b and b=c, then a=c. In your case, comparing #2 to #3 shows no equivalence or equality since they have no matching properties, even though they're both equal to #1.

The short version is that your rules for equality/equivalence cannot be used with any key-based repository, such as Dictionary.

If you're convinced that this is the right way to go, then this will do what you're looking for, but this will not behave consistently. Nothing can behave consistently using this pseudo-equivalence.

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());

However, it's very easy to break this:

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

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

dict[A3] = "baz";

Here, dict[A1] is "baz", as expected. However, dict[A2] is also "baz", even though A2 is not equal to A3 according to these rules. This is because the original object used was A1, which is equal to both.

鸠魁 2024-10-19 22:46:44

要回答您编辑的问题:

创建两个不同的字符串字典(一个用于名称,一个用于代码)并搜索您有值的一个。

To answer your edited question:

Make two different string dictionaries (one for Name and one for Code) and search whichever one you have a value for.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文