24

我已经阅读了有关如何Dictionary.ContainsKey()工作的 MSDN 文档,但我想知道它实际上是如何进行相等比较的?基本上,我有一个以引用类型为键的字典*,我希望该ContainsKey()方法检查该引用类型的某个属性作为确定该键是否存在的基础。例如,如果我有 aDictionary(MyObject, int)并且有一个名为“TypeID”MyObject的公共属性 (of ),我是否可以检查其中一个键的 a是否等于?我可以重载操作员吗?intContainsKey(MyObject myObject)TypeIDmyObject==

  • 引用类型是一个名为“Duration”的对象,它包含一个值 ( double Length);“持续时间”是我的音乐程序中用于表示特定声音持续多长时间的基本类型。我从中派生出包含更复杂时间概念的类,例如西方音乐时间签名,但希望它们在长度方面都具有可比性。

编辑:正如建议的那样,我在我的对象上实现了 IEquitable,如下所示:

 public class Duration : IEquatable<Duration>
 {
    protected double _length;

    /// <summary>
    /// Gets or Sets the duration in Miliseconds.
    /// </summary>
    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
        }
    }

}

这就是我需要做的吗?

4

2 回答 2

12

编辑:这是您更新示例的代码。注意:我觉得将字段公开为受保护的字段,并且还有一个公开成员的虚拟属性有点奇怪。在这种方案下,某些东西可能会覆盖Length导致看起来_lenght不像预期的平等。

public class Duration : IEquatable<Duration>
{
    protected double _length;

    /// <summary>
    /// Gets or Sets the duration in Miliseconds.
    /// </summary>
    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 类使用的默认值的信息,请参见EqualityComparer.Default 。IEqualityComparer

如果你不想在类上普遍覆盖GetHashCodeEquals,或者如果你不能。Dictionary 构造函数有一个重载,您可以在其中提供IEqualityComparer要使用的特定内容。

这是一个简单的实现接口,但您确实需要小心遵守合同,GetHashCode否则您可能会出现意外行为。

public class MyObjectEqualityComparer : IEqualityComparer<MyObject>
{
    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<MyObject, int>(new MyObjectEqualityComparer());   

如果要使用默认的 IEqualityComparer,则需要在 MyObjectEqualityComparer 上提供大致相同的方法。如果您实现IEquatable ,可以避免覆盖。但是我强烈反对它,因为这样做会产生一些令人惊讶的行为。您最好覆盖,以便对 Equals 的所有调用具有一致的行为,并具有正确匹配 Equals 的散列。我不得不修复由过去的开发人员仅实现的继承代码中的错误object.Equals()EqualsIEquatable.

于 2012-11-07T02:13:25.883 回答
9

内部Dictionary使用EqualityComparer. 首先它会检查 key 是否实现IEquatable。如果 key 没有实现这个接口,它会调用Equals方法。

于 2012-11-07T01:53:21.150 回答