Hashtable acting strange

K

Kevin Grigorenko

Thanks for anyone's help on this. First, here is my abbreviated class
structure:

class A {
protected obj myObj;

public override int GetHashCode() {
return myObj.GetHashCode();
}

public override bool Equals(object obj) {
if(obj is B) return myObj.Equals(obj);
return base.Equals(obj);
}
}

class B {
protected string path;

public override int GetHashCode() {
return path.GetHashCode();
}
}

class C : B {...}
class D : B {...}

Now, I have a Hashtable with instances of A as keys. But the Hashtable
isn't working.

Below is some code that got me to come here so baffled. parent is of
type A. The first line always returns null which is my problem. I have
proven that the correct instance of A is in the table during debug (and
the value is not null). The for loop is debug that goes through all of
the Hashtable keys and uses A's Equal() method (which goes to B's) and
it finds the key! Then, I have the key and I execute
(ListViewItem)treeToView[key] and I get null! So I'm walking through
the keys, find the one I want, then use the key from the table and look
up the value, and it's still not there (and the value is not null, I
have stepped to that line, and looked up the value myself in the
table).

Then I printed out the hashes of both the key and the original key
indexer and they are the same.

ListViewItem parentListItem = treeToView[parent] as ListViewItem;
foreach(Tree key in treeToView.Keys)
{
if(key == parent)
{
parentListItem = (ListViewItem)treeToView[key];
bool yes = treeToView.ContainsKey(key);
Console.WriteLine(key.GetHashCode() + "," + parent.GetHashCode());
break;
}
}

I'm at a loss here. The only thing I can see is that A's GetHashCode
calls GetHashCode on an object, not on a type of B. However, since
GetHashCode is virtual, if myObj is of type B then it will call B's
GetHashCode(), not System.Object()'s -- right?

Thanks so much!
Kevin
 
J

Jon Skeet [C# MVP]

Kevin Grigorenko said:
Thanks for anyone's help on this. First, here is my abbreviated class
structure:

class A {
protected obj myObj;

public override int GetHashCode() {
return myObj.GetHashCode();
}

public override bool Equals(object obj) {
if(obj is B) return myObj.Equals(obj);
return base.Equals(obj);
}
}

class B {
protected string path;

public override int GetHashCode() {
return path.GetHashCode();
}
}

That doesn't look good to me - it's not at all obvious that the basic
contracts of GetHashCode and Equals are being met. (Mind you, it's also
not clear what "obj" is meant to be - the type of the "myObj"
variable.)

Could you post a short but complete program which demonstrates the
problem?

See http://www.pobox.com/~skeet/csharp/complete.html for details of
what I mean by that.
 
K

Kevin Grigorenko

Hey Jon,

First, sorry for the typo, obj should have been object. Let me go
create that quick program and see if I can duplicate the effect. If
not, then maybe it is a relic of something in my current code.

I should be back in 10 minutes...

Kevin
 
K

Kevin Grigorenko

Kevin said:
Hey Jon,

First, sorry for the typo, obj should have been object. Let me go
create that quick program and see if I can duplicate the effect. If
not, then maybe it is a relic of something in my current code.

I should be back in 10 minutes...

Kevin

basic

Hey Jon,

Well I tried creating a small test program, but obviously it worked.
That means it is something I'm doing, not the framework. Nevertheless,
I'm at a loss. Now, I'm not going to put my whole program here, but
the following troublesome piece of code and the debug related to it
should be enough as it is quite a contained problem:

Console.WriteLine("Putting in tree: {0}={1}", newChildTree, newItem);
treeToView[newChildTree] = newItem;
treeToView[newChildTree] = newItem;
foreach(object o in treeToView.Keys)
{
Console.WriteLine("o={0},{1}",o.GetHashCode(), o.ToString());
}
Console.WriteLine("Find that item: {0}={1},{2}", newChildTree,
treeToView[newChildTree], treeToView.ContainsKey(newChildTree));


Now, treeToView is the Hashtable, newChildTree is the key, and newItem
is the value.

The output of that piece of code is below. I have added a WriteLine to
my GetHashCode function in Tree, which is the type of the key:

Putting in tree: path1=+ Blogs
Tree::GetHashCode [path1]=1076931875
Tree::GetHashCode [path1]=1076931875
Tree::GetHashCode [path1]=1076931875
o=1076931875,path1
Tree::GetHashCode [path1]=1076931875
o=1076931875,path1
Tree::GetHashCode [path1]=1076931875
Tree::GetHashCode [path1]=1076931875
Find that item: path1=,False


The first interesting thing is that Hashtable.Item overrites values of
the same key; however, here I added the same line twice and got two
keys. That means that it must think the keys are different (even
though they are from the same object and GetHashCode returns the same
value).

I hope that is enough for you to see the problem.

Let me know,
Thanks,
Kevin
 
J

Jon Skeet [C# MVP]

Now, treeToView is the Hashtable, newChildTree is the key, and newItem
is the value.

The output of that piece of code is below. I have added a WriteLine to
my GetHashCode function in Tree, which is the type of the key:

Putting in tree: path1=+ Blogs
Tree::GetHashCode [path1]=1076931875
Tree::GetHashCode [path1]=1076931875
Tree::GetHashCode [path1]=1076931875
o=1076931875,path1
Tree::GetHashCode [path1]=1076931875
o=1076931875,path1
Tree::GetHashCode [path1]=1076931875
Tree::GetHashCode [path1]=1076931875
Find that item: path1=,False


The first interesting thing is that Hashtable.Item overrites values of
the same key; however, here I added the same line twice and got two
keys. That means that it must think the keys are different (even
though they are from the same object and GetHashCode returns the same
value).

I hope that is enough for you to see the problem.

Well, that suggests that you've broken x.Equals(x)==true, for a start.
Try checking what newChildTree.Equals(newChildTree) returns. If it
doesn't return true, that's the first thing to fix.
 
K

Kevin Grigorenko

Jon said:
Now, treeToView is the Hashtable, newChildTree is the key, and newItem
is the value.

The output of that piece of code is below. I have added a WriteLine to
my GetHashCode function in Tree, which is the type of the key:

Putting in tree: path1=+ Blogs
Tree::GetHashCode [path1]=1076931875
Tree::GetHashCode [path1]=1076931875
Tree::GetHashCode [path1]=1076931875
o=1076931875,path1
Tree::GetHashCode [path1]=1076931875
o=1076931875,path1
Tree::GetHashCode [path1]=1076931875
Tree::GetHashCode [path1]=1076931875
Find that item: path1=,False


The first interesting thing is that Hashtable.Item overrites values of
the same key; however, here I added the same line twice and got two
keys. That means that it must think the keys are different (even
though they are from the same object and GetHashCode returns the same
value).

I hope that is enough for you to see the problem.

Well, that suggests that you've broken x.Equals(x)==true, for a start.
Try checking what newChildTree.Equals(newChildTree) returns. If it
doesn't return true, that's the first thing to fix.

Yep, I done went an' broke Equals().

I made the unfortunate assumption that Hashtable only uses an item's
GetHashCode() function to find it, but obviously it uses Equals() as
well.

Thanks Jon!

Kevin
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top