SyncHashtable is not enumerable…

One of the things I really like about working on Mole is that I get to debug some obscure issues that I haven’t come across before. Today, Karl mentioned that there was an issue when dealing with collections – specifically with a synchronized hashtable. Mole was dealing with collections using one of the base collection interfaces – ICollection. He fixed the issue correctly by iterating the IDictionaryEnumerator you get from the IDictionary implementations of a hashtable but I wanted to see what was go on so I decided to look into this further.

The problem can be reproduced with the following snippet:

Hashtable ht = new Hashtable();

Hashtable syncedTable = Hashtable.Synchronized(ht);

IEnumerator enumerator = ((ICollection)syncedTable).GetEnumerator();

Or more likely it would be something like this:

Hashtable ht = new Hashtable();

Hashtable syncedTable = Hashtable.Synchronized(ht);

syncedTable.Add(“Foo”, “Bar”);

EnumerateCollection(syncedTable);

Where EnumerateCollection was something like the following:

private void EnumerateCollection(IEnumerable enumerable)

{

    foreach (object value in enumerable)

    {

        // do something

    }

}

I took at a look at MS’ code for the Hashtable class using Reflector and there is an obvious bug in their implementation. I did a quick internet search and it seems like people have been bitten by this same issue for a while so its hard to believe that it still exists within the framework today. In case anyone encounters the issue, I’ll explain what’s going on.

Hashtable implements the IDictionary interface which derives from ICollection and therefore IEnumerable. Both IDictionary and IEnumerable define a GetEnumerator method. For IDictionary this returns an IDictionaryEnumerator and for IEnumerable this returns an IEnumerator. Hashtable’s implementation of the IDictionary method is a public virtual GetEnumerator method. Its implementation of the IEnumerable method is an explicit implementation of the interface method.

e.g. IEnumerator IEnumerable.GetEnumerator();

The Hashtable class exposes a public static method named Synchronize that is supposed to take a hashtable and return a thread safe hashtable. There are actually flaws in the thread safety aspect of the implementation but that is another matter outside the issue we were dealing with. The Synchronize methods returns an instance of a private nested class named SyncHashtable which derives from Hashtable and is basically a thin wrapper around the Hashtable you pass to the Synchronize method. SyncHashtable overrides the virtual methods on the base Hashtable class and attempts to make dealing with the hashtable thread safe by using locks around edits.

SyncHashtable correctly overrides the public virtual GetEnumerator method and returns the IDictionaryEnumerator of the hashtable its wrapping. However, and herein lies the problem, it does not reimplement the IEnumerable.GetEnumerator method. Therefore, you get the base Hashtable’s implementation which returns an enumerator (HashtableEnumerator) for the SyncHashtable itself. This enumerator class assumes that the buckets member variable of the Hashtable it is to enumerate is non-null but the SyncHashtable specifically uses an overload of the Hashtable constructor that does not initialize this member (and others normally initialized for a Hashtable). It makes sense that they would not want to initialize these values since the SyncHashtable doesn’t store its own values – remember its just a thin wrapper around the Hashtable you provided to the Synchronize method – but then they should have reimplemented the IEnumerable.GetEnumerator method.

So if you’re writing any code that enumerates collections using the IEnumerable interface (directly or indirectly) with an object where you’re not in control of the source, you may want to consider dealing with the IDictionary’s enumerator first.

So you could fix the EnumeratorCollection method above as follows:

private void EnumerateCollection(IEnumerable enumerable)

{

    IEnumerator enumerator;

 

    // SyncHashtable has a bug where its IEnumerable

    // returns an enumerator whose ctor causes a crash.

    // instead, we can get around the problem using its 

    // IDictionary.GetEnumerator impl

    Hashtable table = enumerable as Hashtable;

 

    if (null != table)

        enumerator = table.GetEnumerator();

    else

        enumerator = enumerable.GetEnumerator();

 

    while (enumerator.MoveNext())

    {

        object value = enumerator.Current;

 

        // do something

    }

}

Advertisements

6 Responses to “SyncHashtable is not enumerable…”

  1. Josh Smith Says:

    Nice find. I wonder why Microsoft has not fixed this. Would fixing it introduce a breaking change? This seems like a pretty “core issue” to leave in the framework version after version…

    Thanks for the post.

    Josh

  2. Mole v4.2 Update Released - New Features!! « Karl On WPF - .Net Says:

    […] While I was adding the new Workflow Test Bench program and getting Mole and WF all figured out, I ran into a bump in the carpet. I finally figured out what was causing the program. Andrew Smith of Team Mole has blogged about this issue and you can read his blog entry SyncHashtable is not enumerable… […]

  3. agsmith Says:

    I have to believe that no one reported the issue to MS because there doesn’t seem to be any reason not to fix it. Most people probably wouldn’t even hit it. I may have misnamed the title of the blog because technically its not enumerable if you’re explicitly dealing with ICollection or IEnumerable. If you’re dealing with the Hashtable type directly or even the IDictionary interface, you can do a foreach and it will work since they’ll deal with the GetEnumerator that returns a IDictionaryEnumerator (which derives from IEnumerator).

  4. Gypyvgvp Says:

    Just over two years site lolita13info lolita russian >:]

  5. Oisyrzed Says:

    I’ve just started at http://upugeeuu.de.tl prettens topmodels Mr. Mark is another mofo that gets all the good ass. Look at her fat ass this dude is having a ball.

  6. Jxwlbglc Says:

    I can’t hear you very well http://qunopofytieh.de.tl illegal gay bbs terrible – pixelated so bad its hard to tell if she is in fact asian at all. i doubt she is.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


%d bloggers like this: