简体   繁体   English

词典使用是自定义键,但键始终不相等

[英]Dictionary using is custom key but key is always unequal

I am using RTBTextPointer as custom key in dictionary... 我正在使用RTBTextPointer作为字典中的自定义键...

   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, 我将这个RTBTextPointer和RTBTextPointerComparer类放在类库中,并在不同的wpf项目中使用它,

 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()" 每次containsKey都返回false,即使包含它也是如此,因此在字典中出现重复项。.在我的“ 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 请帮我谢谢

Your problem probably stems from the following declarations in RTBTextPointer : 您的问题可能源于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 . 现在,这些变量引用了RTBTextPointer static成员。 This means that any access of them will access or mutate the static members of it. 这意味着对它们的任何访问都会访问或更改其static成员。 static members are accessible to every instance of a type. static成员可用于类型的每个实例。 If you make them private , they will apply per instance, which I believe is your intent. 如果将它们private ,则它们将适用于每个实例,我相信这是您的意图。

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 . 一旦更正了这一点,至少如果您打算将其用作Dictionary的键,我将重新考虑您的类的设计。 RTBTextPointer should be immutable, or atleast the fields and properties that GetHashCode() depends on. RTBTextPointer应该是不可变的,或者至少是GetHashCode()依赖的字段和属性。 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". 假设我们有一些任意键RTBTextPointerRow = 2Column = 2并且值为“ Foo”。 It's GetHashCode would be 0 (2 XOR 2). 它的GetHashCode将为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) . 现在,对Dictionary.ContainsKey()的调用将在寻找RTBTextPointer(2,2)返回true。 Now consider if this RTBTextPointer changed to have a Row = 4 . 现在考虑是否将此RTBTextPointer更改为Row = 4 It's hash code would now be 6 (4 XOR 2). 它的哈希码现在为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. 现在,对Dictionary.ContainsKey()的调用将为false,并且值Foo将不可访问,因为该键具有取决于可变状态的哈希码。

As a final note, I would consider overriding the Equals() and GetHashCode() methods of object . 最后一点,我将考虑重写objectEquals()GetHashCode()方法。

I don't think you need to create a separate comparer. 我认为您不需要创建单独的比较器。 Just overriding Equals and GetHashCode should suffice. 仅覆盖EqualsGetHashCode就足够了。

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: 如果您有两个以上的属性,并且这些属性可以为null,则GetHashCode可能如下所示:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM