Dictionary.ContainsKey() – 它是如何工作的?
我已经阅读了关于Dictionary.ContainsKey()
如何工作的MSDN文档,但我想知道它是如何实际进行相等比较的? 基本上,我有一个键入引用类型*的字典,我希望ContainsKey()
方法检查该引用类型的某个属性作为确定密钥是否存在的基础。 例如,如果我有一个Dictionary(MyObject, int)
并且MyObject
有一个名为“TypeID”的公共属性( int
),我是否可以获取ContainsKey(MyObject myObject)
以检查其中一个键是否具有TypeID
等于myObject
? 我可以重载==
运算符吗?
- 引用类型是一个名为“Duration”的对象,它保存一个值(
double Length
); “持续时间”是我的音乐节目中使用的基本类型,表示特定声音持续多长时间。 我从中派生出类,其中包含更复杂的时序概念,如西方音乐时间签名,但希望所有这些概念在长度方面具有可比性。
编辑:正如所建议的,我在我的对象上实现了IEquitable,如下所示:
public class Duration : IEquatable { protected double _length; /// /// Gets or Sets the duration in Miliseconds. /// public virtual double Length { get { return _length; } set { _length = value; } } // removed all the other code that as it was irrelevant public override bool Equals(object obj) { Duration otherDuration = (Duration)obj; if (otherDuration._length == _length) { return true; } else { return false } } }
这就是我需要做的吗?
编辑:这是您更新的示例的代码。 注意:我觉得将字段公开为受保护有点奇怪,并且还有一个公开该成员的虚拟属性。 在这个方案下,有些东西可以覆盖Length
导致相等,看起来_lenght
不能按预期运行。
public class Duration : IEquatable { protected double _length; /// /// Gets or Sets the duration in Miliseconds. /// public virtual double Length { get { return _length; } set { _length = value; } } // removed all the other code that as it was irrelevant public bool Equals(Duration other) { // First two lines are just optimizations if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; return _length.Equals(other._length); } public override bool Equals(object obj) { // Again just optimization if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; // Actually check the type, should not throw exception from Equals override if (obj.GetType() != this.GetType()) return false; // Call the implementation from IEquatable return Equals((Duration) obj); } public override int GetHashCode() { // Constant because equals tests mutable member. // This will give poor hash performance, but will prevent bugs. return 0; } }
有关Dictionary类使用的默认IEqualityComparer
信息,请参见EqualityComparer.Default 。
如果您不希望通常在类上覆盖GetHashCode
和Equals
,或者您不能。 Dictionary构造函数有一个重载 ,您可以在其中提供要使用的特定IEqualityComparer
。
它是一个简单的实现接口,但您需要注意尊重GetHashCode
的合同,否则最终会出现意外行为。
public class MyObjectEqualityComparer : IEqualityComparer { public bool Equals(MyObject x, MyObject y) { return x.TypeID == y.TypeID; } public int GetHashCode(MyObject obj) { return obj.TypeID; //Already an int } }
使用它只是去
new Dictionary(new MyObjectEqualityComparer());
如果要使用默认的IEqualityComparer,则需要在MyObjectEqualityComparer上提供大致相同的方法。 如果实现IEquatable, 则可以避免覆盖object.Equals object.Equals()
。 但是我强烈反对它,因为这样做会产生一些令人惊讶的行为。 您最好覆盖Equals
以便对所有对Equals的调用具有一致的行为,并且具有与Equals正确匹配的散列。 我不得不修复由过去的开发人员实现IEquatable.
导致的inheritance代码中的错误IEquatable.
内部Dictionary
使用EqualityComparer
。 首先,它将检查密钥是否实现IEquatable
。 如果key没有实现此接口,它将调用Equals
方法。