作者:爷_引领霸气 | 来源:互联网 | 2023-05-18 12:31
Hashtable是怎样工作的?我尝试将string对象包装到一个自定义类中,并重载自定义类的GetHashCode()和Equals(object)使它模拟string去工作。如下:cl
Hashtable是怎样工作的?
我尝试将string对象包装到一个自定义类中,并重载自定义类的GetHashCode()和Equals(object)使它模拟string去工作。
如下:
class Wrapper {
private string text;
public Wrapper(string text) {
this.text = text;
}
public override int GetHashCode() {
return this.text.GetHashCode();
}
public override bool Equals(object obj) {
return this.text.Equals(obj);
}
}
但当我用Wrapper类的实例作为key和value添加到Hashtable中的时候,出现了令人费解的情况:
Hashtable table = new Hashtable();
Wrapper key = new Wrapper("key");
Wrapper value = new Wrapper("value");
table.Add(key, value);
table.Contains("key"); // 这里返回true
table.ContainsKey("key"); //这里返回true
table.ContainsValue("value"); //这里返回了false !!!
ICollection vals = table.Values;
foreach (Wrapper w in vals) {
w.Equals("key"))); //这里返回了true!!!
}
foreach (DictionaryEntry e in table) {
e.Key.Equals("key"); // 这里返回了true
e.Value.Equals("value");//这里也返回了true
}
哪位大侠能解释一下?万分感谢!
19 个解决方案
上面倒数第6行 w.Equals("key")));应该是w.Equals("value");
public override bool Equals(object obj) {
return this.text.Equals(obj);
}
你这个明显就是错的。。
string str = (string)obj;
return this.text == str;
Equals有什么问题吗?相同的string看做同一个key
table.ContainsValue("value"); //这里返回了false !!!
From MSDN:
public virtual bool ContainsValue(
object value
);
The values of the elements of the Hashtable are compared to the specified value using the Object.Equals method.
这说明了当你执行table.ContainsValue(Object object)是,它内部调用的是object.Equals function, 在你的程序里是string.Equals而不是你期望的Wrapper.Equals. 当然return false
>public override bool Equals(object obj) {
> return this.text.Equals(obj);
> }
>
>你这个明显就是错的。。
>
>string str = (string)obj;
>return this.text == str;
这个不错. C# compiler 会自动把漏掉的补上.
这就是为啥这段没错:
foreach (Wrapper w in vals) {
w.Equals("value"))); //这里返回了true!!!
}
foreach (DictionaryEntry e in table) {
e.Key.Equals("key"); // 这里返回了true
e.Value.Equals("value");//这里也返回了true
}
嗯。。刚刚看了一下,ContainsValue比较的是对象的引用,而不是值的比较。实际使用的是
object.Equals(..)方法。这样的情况下,只有是同一个对象的情况下,才会返回true.
> 嗯。。刚刚看了一下,ContainsValue比较的是对象的引用,而不是值的比较。实际使用的是
> object.Equals(..)方法。这样的情况下,只有是同一个对象的情况下,才会返回true.
非也. 所有Equals都是值的比较,不管谁调他.
string是object的子类. Equals又是virtual的,调的时候会调到string.Equals.
他的问题是,他想比较一个hashtable内部的Wrapper和一个输入的string.
他认为被调用的是Wrapper.Equals但实际被调用的是string.Equals
非也. 所有Equals都是值的比较,不管谁调他.
Equals的默认实现当然仅仅是引用的比较,要实现实现值的比较,必须自己在派生类中重写。这个是毫无疑问的。
他的问题是,他想比较一个hashtable内部的Wrapper和一个输入的string.
他认为被调用的是Wrapper.Equals但实际被调用的是string.Equals
最终调用的既不是Wrapper.Equals,也不是string.Equals,仅仅是Object.Equals(obj)
仅此而已。。。 。。。
非也. 所有Equals都是值的比较,不管谁调他.
对于.NET中固有的值类型,已经重写了Equals,在重载函数中进行了值的比较。
对于类类型,仅仅是引用而已。。。 。。。
自定义类中,想要在Equals中实现值的比较,除非你自己重新实现。。。。。。。。。。。。
Equals的默认实现是return false. Equals就是为了值比较而存在的.
如果要用引用比较,使用object.ReferenceEquals.
所有implement Object.Equals的系统类,都把他写成了值比较.
>> 最终调用的既不是Wrapper.Equals,也不是string.Equals,仅仅是Object.Equals(obj)
他既然输入了一个string的对像,被调用的当然是string.Equals.
>自定义类中,想要在Equals中实现值的比较,除非你自己重新实现。。。。。。。。。。。。
这个不错.
我的意思是Equals就是应该被重新实现成某种值的比较, 如果你把他重新实现成引用比较,那就不对
一头雾水。。。我现在的遇到问题是使用重载了GetHashCode和Equals之后的Wrapper做对象加入Hashtable的时候,用Values或Enumerator遍历可以找到值,而使用索引器item[key]就返回空。。。
写成这样:
class Wrapper {
private string text;
public Wrapper(string text) {
this.text = text;
}
public override string ToString() {
return text;
}
public override int GetHashCode() {
return this.text.GetHashCode();
}
public override bool Equals(object obj) {
return this.text.Equals(obj.ToString());
}
}
然后,不要直接用string, 改用Wrapper
例如:
table[new Wrapper("key")]
HashTable在使用ContainsValue来检查时,使用的是参数的Equals方法。
如果参数是string,则是值的比较,因为string重写了Equals,实现了值的比较的行为,因为string是基于一种值的概念的。
除string外。.NET的系统类均没有重写Equals,也就是说,都是引用的比较。
所以如果是自定义的类,那ContainsValue就取决于你参数类的Equals的实现了。没有重写Equals,也不是string类型,那就是引用的比较。
嗯。归根结底。应该使用正确的参数类型来调用ContainsValue方法。
嗯. silentfish要是理解了就给分吧, 我穷啊 :-)
你的Wrapper类需要重写Equals与GetHashCode.