Dictionary using is custom key but key is always unequal

。_饼干妹妹 提交于 2019-12-09 07:31:24

I don't think you need to create a separate comparer. Just overriding Equals and GetHashCode should suffice.

Also, if you have very simple properties like that, you could switch to auto properties

public class RTBTextPointer
{
    public int Row
    {
        get;
        set;
    }
    public int Column
    {
        get;
        set;
    }
    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj))
        {
            return false;
        }
        if (ReferenceEquals(this, obj))
        {
            return true;
        }
        var other = obj as RTBTextPointer;
        if (other == null)
        {
            return false;
        }
        return other.Row == Row && other.Column == Column;
    }
    public override int GetHashCode()
    {
        unchecked
        {
            // 397 or some other prime number
            return (Row * 397) ^ Column;
        }
    }
}

See unchecked for more information about that.

If you have more than two properties, and if those properties could be null, the GetHashCode might look like this:

unchecked
{
    var result = 0;
    result = (result * 397) ^ (Prop1 != null ? Prop1.GetHashCode() : 0);
    result = (result * 397) ^ (Prop2 != null ? Prop2.GetHashCode() : 0);
    result = (result * 397) ^ (Prop3 != null ? Prop3.GetHashCode() : 0);
    result = (result * 397) ^ (Prop4 != null ? Prop4.GetHashCode() : 0);
    // ...
    return result;
}

Your problem probably stems from the following declarations in RTBTextPointer:

static int _row;
static int _column;

These don't do what I think you're intending. They should be

private int _row; 
private int _column; 

As it is right now, these variables reference static members of RTBTextPointer. This means that any access of them will access or mutate the static members of it. static members are accessible to every instance of a type. If you make them private, they will apply per instance, which I believe is your intent.

Once that is corrected, I would reconsider the design of your class, at least if you intent to use it as a key in a Dictionary. RTBTextPointer should be immutable, or atleast the fields and properties that GetHashCode() depends on. Here's why:

When you add a object as a key to a dictionary, it's associated value is placed in a hash bucket , which is simply some data structure associated with a hash code. Assume we have some arbitrary key RTBTextPointer with Row = 2 and Column = 2 and a value of "Foo". It's GetHashCode would be 0 (2 XOR 2).

Hash Key                  Value
0    RTBTextPointer(2,2)  Foo

Right now, a call to Dictionary.ContainsKey() would return true looking for RTBTextPointer(2,2). Now consider if this RTBTextPointer changed to have a Row = 4. It's hash code would now be 6 (4 XOR 2). The call to Dictionary.ContainsKey() would now be false, and the value Foo would be inaccessible because the key has a hash code that depends upon mutable state.

As a final note, I would consider overriding the Equals() and GetHashCode() methods of object.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!