8

该程序正在使用此实现:

class Instrument
{
    public string ClassCode { get; set; }
    public string Ticker { get; set; }
    public override string ToString()
    {
        return " ClassCode: " + ClassCode + " Ticker: " + Ticker + '.';
    }
}

但是因为我需要在 Dictionary 中使用 Instrument,所以我决定实现 equals/hashcode:

class Instrument
{
    public string ClassCode { get; set; }
    public string Ticker { get; set; }
    public override string ToString()
    {
        return " ClassCode: " + ClassCode + " Ticker: " + Ticker + '.';
    }

    public override bool Equals(object obj)
    {
        if (obj == null)
            return false;

        Instrument instrument = obj as Instrument;
        if (instrument == null)
            return false;

        return ((ClassCode.Equals(instrument.ClassCode)) && (Ticker.Equals(instrument.Ticker));
    }

    public override int GetHashCode()
    {
        int hash = 13;
        hash = (hash * 7) + ClassCode.GetHashCode();
        hash = (hash * 7) + Ticker.GetHashCode();
        return hash;
    }
}

现在该程序已停止工作。在这样或类似的地方,我收到“KeyNotFoundException”:

if (cache.Keys.Any(instrument => instrument.Ticker == newTicker && instrument.ClassCode == newClassCode))

是否有可能某些代码假定未实现等于和哈希码?或者我可能只是错误地实施了它们?抱歉,我不熟悉 C# 中的最后一段代码这样的高级功能,也不知道它是如何与 equals 或 hashCode 连接的。

4

3 回答 3

7

你的 HashCode 和 Equals 方法应该只依赖于不可变的属性——你的实现使用 ClassCode 和 Ticker,它们都有设置器,因此是可变的。

于 2011-04-18T08:42:47.470 回答
3

首先cache.Keys.Any,您可以只使用ContainsKey而不是使用。

bool contains = cache.ContainsKey(
    new Instrument { Ticker = newTicker, ClassCode = newClassCode });

第一个迭代整个键列表 - O(n),而第二个使用 Dictionary 的内置哈希表实现 - O(1)。

其次,在您的实现中检查空引用:

public override bool Equals(object obj)
{
    if (obj == null)
        return false;

    Instrument instrument = obj as Instrument;
    if (instrument == null)
        return false;

    // 1. string.Equals can handle null references.
    // 2. object.ReferenceEquals for better preformances when it's the same object
    return (object.ReferenceEquals(this, instrument)) ||
        (string.Equals(ClassCode, instrument.ClassCode) &&
        string.Equals(Ticker, instrument.Ticker));
}

public override int GetHashCode()
{
    int hash = 13;
    if (ClassCode != null)
        hash = (hash * 7) + ClassCode.GetHashCode();
    if (Ticker!= null)
        hash = (hash * 7) + Ticker.GetHashCode();

    return hash;
}

除此之外,我看不出有什么问题。

于 2011-04-18T08:31:14.287 回答
1

但是因为我需要在 Dictionary 中使用 Instrument 我决定实现 equals/hashcode

那是错误的原因。您的课程已经具有适用于、高效且经过测试可在字典中使用的 Equality 和 GetHashCode 实现。

我是否正确实现了 Equals()/GetHashCode()?

不,你一开始就错过了一个重载==。只有当您使 Instrument 不可变时,它才会可靠。

您最好的做法是不要覆盖任何这些成员。

另请参阅此 MSDN 建议。注意“平等保证”和

不建议在非不可变类型中覆盖 operator ==。

于 2011-04-18T10:11:44.367 回答