问题
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