0

我创建了一种字符串包装类,并希望将其实例用作字典键,与常用字符串互换。我超越GetHashCodeEquals得到了看起来很奇怪的结果。我已经隔离了这个问题。请查看我的代码并解释为什么第二次查找返回 null。

void Main()
{
    var foo = new StringWrapper("foo");
    var h = new Hashtable {{ foo, "bar" }};
    Console.WriteLine(h["foo"]);
    Console.WriteLine(h[foo]); // null ??
}

public class StringWrapper
{
    readonly string wrapped;
    public StringWrapper(string s) {
        wrapped = s;
    }
    public override bool Equals(object obj) {
        return wrapped.Equals(obj);
    }
    public override int GetHashCode() {
        return wrapped.GetHashCode();
    }
    public override string ToString() {
        return wrapped;
    }
}
4

3 回答 3

6

请记住, in Equals(object obj)obj不会是 a string,而是 a StringWrapper- 并且 astring永远不会说它等于不是 a 的东西string。您需要从obj. 请记住,您应该检查null并考虑到如果有人使用StringWrapper其他东西而不是将其放入哈希表中,obj也可能是任何其他类型。

于 2012-08-21T17:38:22.697 回答
3

您的平等实现不是对称的,也不是自反的:

StringWrapper wrapper = new StringWrapper("foo");

Console.WriteLine(wrapper.Equals(wrapper)); // False
Console.WriteLine(wrapper.Equals("foo")); // True
Console.WriteLine("foo".Equals(wrapper)); // False

因此,您违反了文档中为Object.Equals. Hashtable(和其他类)希望您不要违反这些规则,并且当您违反它们时将无法正常工作。

听起来您需要一个自定义集合,而不是一个试图假装包装器等于原始值的包装器。

(顺便说一句,你为什么还在使用非泛型Hashtable而不是Dictionary<,>?)

于 2012-08-21T17:41:11.190 回答
1

问题是您的 Equals 方法:

public override bool Equals(object obj) {
    // wrapped is a String, but obj is (usually) a StringWrapper
    return wrapped.Equals(obj);
}

你需要这样的东西:

public override bool Equals(object obj) {
    var other = obj as StringWrapper;
    return other != null && wrapped.Equals(other.wrapped);
}

编辑:根据乔恩的回答,您可能还希望能够与字符串进行比较:

public override bool Equals(object obj) {
    var other = obj as StringWrapper;
    return (other != null && wrapped.Equals(other.wrapped))
           || Object.Equals(wrapped, (obj as String));
}
于 2012-08-21T17:39:04.247 回答