我想使用自定义对象作为Dictionary键,主要是,我有这样的事情:(我不能使用.net 4.0所以我没有元组)
class Tuple<A, B> : IEquatable<Tuple<A,B>>
{
public A AValue { get; set; }
public B BValue { get; set; }
public Tuple(A a, B b){ AValue = a; BValue = b; }
public bool Equals(Tuple<A, B> tuple)
{
return tuple.AValue.Equals(AValue) && tuple.BValue.Equals(BValue);
}
public bool Equals(object o)
{
return this.Equals(o as Tuple<A,B>);
}
}
Run Code Online (Sandbox Code Playgroud)
然后我做这样的事情.
var boolmap = new Dictionary<Tuple<bool, bool>, string>();
boolmap.Add(new Tuple<bool,bool>(true, true), "A");
boolmap.Add(new Tuple<bool,bool>(true, false), "B");
boolmap.Add(new Tuple<bool,bool>(false, true), "C");
boolmap.Add(new Tuple<bool,bool>(false, false), "D");
var str = boolmap[new Tuple<bool,bool>(true, false)];
Run Code Online (Sandbox Code Playgroud)
我在最后一行得到了一个KeyNotFound异常.为什么是这样 ?我实现IEquatable是不够的?
谢谢
cdh*_*wie 34
您还需要覆盖GetHashCode()(最好也是Equals()).您的其他对象正在返回不同的哈希码,这意味着在查找时找不到该键.
该GetHashCode()合同规定,从两个对象的返回值必须等于当两个对象被认为是相等的.这是你问题的根源; 你的班级不符合这个要求.如果它们不相等,则合同不指定该值必须不同,但这将提高性能.(如果所有对象都返回相同的哈希码,您也可以从性能角度使用平面列表.)
在您的情况下,一个简单的实现可能是:
public override int GetHashCode()
{
return AValue.GetHashCode() ^ BValue.GetHashCode();
}
Run Code Online (Sandbox Code Playgroud)
请注意,这可能是一个好主意,以测试AValue或者BValue是null.(这将是有点复杂,因为你不约束泛型类型A和B,所以你不能只值比较null-类型可以是值类型,例如)1
将您打算用作字典键的类创建为不可变的也是一个好主意.如果更改正用作键的对象的值,则字典将显示奇怪的行为,因为该对象现在位于不属于它的存储桶中.
1请注意,您可以在此处使用EqualityComparer<A>.Default.GetHashCode(AValue)(和类似的BValue),因为这将消除对空检查的需要.
| 归档时间: |
|
| 查看次数: |
36800 次 |
| 最近记录: |