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

C# Dictionary.ContainsKey()-它是如何工作的?,c#,.net,reference-type,idictionary,C#,.net,Reference Type,Idictionary,我已经阅读了有关Dictionary.ContainsKey()如何工作的MSDN文档,但我想知道它实际上是如何进行等式比较的?基本上,我有一个指向引用类型*的字典,我希望ContainsKey()方法检查该引用类型的某个属性,作为确定键是否存在的基础。例如,如果我有一个字典(MyObject,int)并且MyObject有一个名为“TypeID”的公共属性(属于int),我是否可以让ContainsKey(MyObject-MyObject)检查其中一个键是否有一个TypeID等于MyObje

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

  • 引用类型是一个名为“Duration”的对象,它保存一个值(
    双倍长度
    );“持续时间”是我的音乐节目中使用的一种基本类型,表示特定声音持续的时间。我从中衍生出一些课程,这些课程包含了更复杂的计时概念,比如西方音乐的时间签名,但我希望所有这些课程在长度上都具有可比性
编辑:根据建议,我在我的对象上实现了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
        }
    }

}
public类持续时间:i足够
{
保护双倍长度;
/// 
///获取或设置以毫秒为单位的持续时间。
/// 
公共虚拟双倍长度
{
得到
{
返回长度;
}
设置
{
_长度=值;
}
}
//删除了所有其他不相关的代码
公共覆盖布尔等于(对象对象对象)
{
持续时间otherDuration=(持续时间)obj;
如果(其他持续时间._长度=_长度)
{
返回true;
}
其他的
{
返回错误
}
}
}

这就是我需要做的吗?

内部
字典
使用
EqualityComparer
。首先,它将检查键是否执行。如果键未实现此接口,它将调用
Equals
方法。

编辑:以下是更新示例的代码。注意:我觉得有点奇怪,您将字段公开为受保护的,并且还有一个公开成员的虚拟属性。在该方案下,某些内容可能会覆盖
长度
,从而导致在
\u Length
上看起来不符合预期的相等

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;
    }
}
要使用它,就去吧

new Dictionary<MyObject, int>(new MyObjectEqualityComparer());   
新字典(新MyObjectEqualityComparer());

如果要使用默认的IEqualityComparer,则需要在MyObject EqualityComparer上提供大致相同的方法。如果您实现,您可以避免重写
对象.Equals()
。然而,我强烈反对这样做,因为这样做会产生一些令人惊讶的行为。您最好重写
Equals
,以便对Equals的所有调用都具有一致的行为,并使哈希正确匹配Equals。我必须修复继承代码中的一个bug,该bug是由以前的开发人员仅实现
IEquatable造成的。

您必须根据需要重载GetHashCode和Equals<代码>=根本不使用。请参阅其他相关问题-例如,您还必须确保
GetHashCode
函数在每个对象实例的整个生命周期内始终返回相同的值。如果哈希代码基于属性值,则建议您将引用对象设置为不可变。@Richard,我已编辑了我的答案,为您更新的示例添加了注释代码示例。它没有检查此项。它总是调用
GetHashCode
(导航到存储桶链),然后
Equals
(直接比较)可以指定或默认的
EqualityComparer
方法。@2kay,我的意思是
EqualityComparer
检查键是否实现了
IEquatable
。我明白了。但似乎它并没有真正检查这一点。不管msdn怎么说,在反编译的
字典中搜索
IEquatable
(以及所有默认的
EqualityComparer
s)都不会得到任何结果。@2可以,检查
EqualityComparer.CreateComparer()
方法。它包含行
if(typeof(IEquatable).IsAssignableFrom((Type)genericParameter1))
.Hm,真的。只是选择比较器。很抱歉:)你最好返回
TypeID.GetHashCode()
@2Kay。TypeID是一个int。调用
GetHashCode()
一个int可以得到什么值?我自己刚刚得到了类似的结果,尽管你的版本要好得多。不过有几个问题:为什么不直接返回双倍长度而不是零的散列码呢?什么样的错误会出现?另外,您是否让对象对其自身执行空引用检查,并使用“if(ReferenceEquals(this,other))返回true”?如果是,并且为空(可能吗?),为什么要返回true而不是false?@Richard。我不太明白你的第二个问题。你是在问这是否可以为空吗?简单的答案是否定的。@Richard这里的第一个问题是一种可能性,为了简洁起见,我使用HashMap而不是Dictionary(两者都是使用哈希实现的)<代码>变量d=新的持续时间{Length=5}
var-map=newhashmap()
map.Add(d);map.Contains(d)/*返回true(预期)*/
d.Length=7
map.Contains(d)/*返回false(意外)*/
您从未从映射中删除d,因此您希望它仍然存在,但您更改了哈希代码,使其在映射中查找修改的d的哈希代码时找不到它。您可能需要查找哈希或哈希表。
new Dictionary<MyObject, int>(new MyObjectEqualityComparer());