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

本文关键字:不相等 字典 自定义 | 更新日期: 2023-09-27 18:30:14

我正在使用RTBTextPointer 作为字典中的自定义键...

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

我在类库中使用这个RTBTextPointer和RTBTextPointerComparer类,并在不同的wpf项目中使用它,

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

每次包含密钥都返回 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;
    }
}

请帮助我提前致谢

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

我认为您不需要创建一个单独的比较器。只需覆盖EqualsGetHashCode就足够了。

另外,如果您有非常简单的属性,则可以切换到自动属性

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

有关此内容的更多信息,请参阅未选中。

如果有两个以上的属性,并且这些属性可能为 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;
}

您的问题可能源于RTBTextPointer中的以下声明:

static int _row;
static int _column;

这些并没有按照我认为的意图去做。他们应该是

private int _row; 
private int _column; 

就像现在一样,这些变量引用static RTBTextPointer 的成员。这意味着它们的任何访问都将访问或改变其static成员。 static成员可供类型的每个实例访问。如果您将它们设为private,它们将按实例应用,我相信这是您的意图。

一旦纠正了这一点,我会重新考虑你的类的设计,至少如果你打算把它用作Dictionary中的键。 RTBTextPointer应该是不可变的,或者至少是不可变的,或者至少是GetHashCode()依赖的字段和属性。原因如下:

当你将一个对象作为键添加到字典时,它的关联值被放置在哈希桶中,这只是一些与哈希代码关联的数据结构。假设我们有一些任意键RTBTextPointer,带有 Row = 2Column = 2,值为 "Foo"。它的GetHashCode将是0(2 XOR 2)。

Hash Key                  Value
0    RTBTextPointer(2,2)  Foo

现在,打电话给Dictionary.ContainsKey()会返回真正的寻找RTBTextPointer(2,2)。现在考虑一下这个RTBTextPointer是否更改为具有Row = 4。它的哈希代码现在是 6(4 XOR 2)。对Dictionary.ContainsKey()的调用现在将为 false,并且Foo的值将无法访问,因为密钥具有依赖于可变状态的哈希代码。

最后,我会考虑覆盖objectEquals()GetHashCode()方法。