开发者

Object as key in Dictionary

开发者 https://www.devze.com 2023-02-04 20:08 出处:网络
I have this class: class A { string name; 开发者_运维问答string code; } Examples: A1: name=\"blabla\", code=\"kuku\"

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?


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).


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.


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消