Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Struct casting behavior different between for and foreach loops

Tags:

c#

I came across this bizarre situation just now: I was editing some legacy code which looks something like this:

Hashtable hashtable = GetHashtable();

for (int i = 0; i < hashtable.Count; i++)
{
    MyStruct myStruct = (MyStruct)hashtable[i];

    //more code
}

Now when changing this to a foreach loop:

var hashtable = GetHashtable();

foreach (var item in hashtable)
{
    var myStruct = (MyStruct)item;

    //more code
}

I had assumed the behavior would be the same, however, I get System.InvalidCastException: Specified cast is not valid.

What is the reason for this different behavior?

like image 355
dav_i Avatar asked Nov 24 '25 08:11

dav_i


2 Answers

Iterating a Hashtable doesn't iterate its values, rather it iterates key value pairs as a DictionaryEntry object.

Instead try iterating on its .Values collection instead.

foreach (var item in hashtable.Values)
{
    var myStruct = (MyStruct)item;
}

Since you are refactoring old legacy code, if possible, you should also consider using the generic Dictionary<TKey, TValue> instead. It will take advantage of struct value semantics and avoid boxing.


If you wanted to iterate on the DictionaryEntry objects, you can do so but will need to cast to it as well as your MyStruct:

foreach (DictionaryEntry entry in hashtable)
{
    var myStruct = (MyStruct)entry.Value;
}

Finally, there's the Linq solution, but it may not be applicable for you since this is legacy code; it may not be available:

foreach(var myStruct in hashtable.Values.Cast<MyStruct>())
{

}
like image 98
Chris Sinclair Avatar answered Nov 26 '25 19:11

Chris Sinclair


Each yielded item in a Hashtable is a DictionaryEntry. Therefore you can also do it like this

foreach (DictionaryEntry de in hashtable)
{
    var myStruct = (MyStruct)de.Value;
    //more code
}
like image 40
Ehsan Avatar answered Nov 26 '25 18:11

Ehsan