Dictionary.ContainsKey() - 它是如何工作的?

Ric*_*ard 21 .net c# idictionary reference-type

我已经阅读了关于如何Dictionary.ContainsKey()工作的MSDN文档,但我想知道它实际上是如何进行相等比较的?基本上,我有一个键入引用类型*的字典,我希望该ContainsKey()方法检查该引用类型的某个属性作为确定密钥是否存在的基础.举例来说,如果我有一个Dictionary(MyObject, int)MyObject拥有(的公共财产int被称为"TYPEID"),我能得到ContainsKey(MyObject myObject)检查,看是否的关键之一具有TypeID等于myObject?我可以超载==操作员吗?

  • 引用类型是一个名为"Duration"的对象,它包含一个value(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
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

这就是我需要做的吗?

vos*_*d01 11

编辑:这是您更新的示例的代码.注意:我觉得将字段公开为受保护有点奇怪,并且还有一个公开该成员的虚拟属性.在这种方案下,有些东西可以覆盖,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;
    }
}
Run Code Online (Sandbox Code Playgroud)

有关Dictionary类使用的默认值的信息,请参见EqualityComparer.DefaultIEqualityComparer.

如果你不想一般覆盖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
    }
}
Run Code Online (Sandbox Code Playgroud)

使用它只是去

new Dictionary<MyObject, int>(new MyObjectEqualityComparer());   
Run Code Online (Sandbox Code Playgroud)

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


Kir*_*huk 7

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