Dictionary using is custom key but key is always unequal

孤人 提交于 2019-12-23 03:34:06

问题


I am using RTBTextPointer as custom key in dictionary...

   Init.SpintaxEditorPropertyMain.SpintaxListDict = new Dictionary<RTBTextPointer, SpintaxEditorProperties.SpintaxMappedValue>(new RTBTextPointerComparer());

I worte this RTBTextPointer, and RTBTextPointerComparer classes in class library and using this in different wpf projects,

 if (Init.SpintaxEditorPropertyMain.SpintaxListDict.ContainsKey(_index) == false)
        {
            Init.SpintaxEditorPropertyMain.SpintaxListDict.Add(_index,_SpintaxMappedVal);
        }

everytime containsKey returns false, even it contains, so duplication entry occurs in dictionary.. is anything wrong in my "GetHashCode()"

    public class RTBTextPointer
    {
    static int _row;
    static int _column;

    public int Row
    {
        get
        {
            return _row;
        }
        set
        {
            _row = value;
        }
    }
    public int Column
    {
        get
        {
            return _column;
        }
        set
        {
            _column = value;
        }
    }

}

public class RTBTextPointerComparer : IEqualityComparer<RTBTextPointer>
{
    public bool Equals(RTBTextPointer x, RTBTextPointer y)
    {         
        bool result = int.Equals(x.Column, y.Column) && (int.Equals(x.Row, y.Row));

        return result;
    }

    public int GetHashCode(RTBTextPointer obj)
    {
        var result = 0;
        int hCode = obj.Column ^ obj.Row;
        result = hCode.GetHashCode();
        return result;
    }
}

Please help me Thanks in advance


回答1:


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



回答2:


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.



来源:https://stackoverflow.com/questions/18605476/dictionary-using-is-custom-key-but-key-is-always-unequal

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