How to iterate through keys and values of an `IDictionary`?
Asked Answered
D

2

22

How would I iterate through the keys and values of an IDictionary if I don't know the concrete types of the keys and values within, therefore want to just treat them as objects?

If I do something like:

foreach(var x in myIDictionary) { ... }

I think x is an object. But how would I get the Key and Value out of it (both typed as objects), as specified in the IDictionaryEnumerator? There isn't an IKeyValuePair without generic parameters is there?

I guess I could loop through the enumerator by hand using MoveNext etc, but I feel like there must be a way to do it with foreach!

Dnieper answered 24/3, 2017 at 15:40 Comment(10)
I think x is an object Why don't you check what it actually is, rather than just guessing.Alyssaalyssum
@Alyssaalyssum x IS an object, everything is an object in OOPHexastich
@BernardWalters Servy is well aware of that. His point is that OP hasn't bothered to check what x is before coming here to ask us.Irritate
@BernardWalters It's a type that's derived from an object. It's convertible to "object". The type of x is not "object" though.Alyssaalyssum
The reason I'm not sure is that I don't know for sure where I would find out. Obviously I can find out the concrete type in the debugger, but I don't know what the type is supposed to be? I think it's the type of IDictionaryEnumerator.Current, but is that correct? (I did bother to try - otherwise I wouldn't be on StackOverflow in the first place.)Dnieper
@JosephHumfrey You can look at the documentation for the type if you want to find out what the items are.Alyssaalyssum
Possible duplicate of What is the best way to iterate over a Dictionary in C#?Irritative
everything is an object in OOP A common misconception. C# is a language that carfully follows oop rules most but not all the time. Everything ís an object in other oop languages, like Smalltallk.Haukom
@Alyssaalyssum - see the answers - it's not entirely straightforward (e.g. "there isn't a clear type" v.s. "you can use DictionaryEntry, but not always"). But feel free to point me in the direction of a documentation that clearly gives a definitive answer.Dnieper
@JosephHumfrey I'm entirely confident in your ability to find the documentation for IDictionary on your own. You don't need me (or other answerers) to find it for you.Alyssaalyssum
C
28

You can explicitly specify DictionaryEntry pair type in foreach like this:

foreach (DictionaryEntry x in myIDictionary)

Though you should be sure that it is standard implementation of IDictionary (like Hashtable or Dictionary<TKey, TValue>)

Otherwise it can be literally anything in enumerator.

Cheddar answered 24/3, 2017 at 15:44 Comment(9)
Perhaps this is a nitpick, but there isn't any requirement that IDictionaryEnumerator.Current be a DictionaryEntry and that is what foreach uses. It would be pretty weird if it weren't, but not a violation of the interface.Irritate
I guess my point of confusion is the fact that an IDictionary's enumerator uses DictionaryEntry, and yet a concrete Dictionary<string, int> (for example), would use a KeyValuePair<string, int> (which isn't related to a DictionaryEntry). So the behaviour actually depends on the specific casting of the dictionary variable that you iterate.Dnieper
@Irritate yes, indeedCheddar
@JosephHumfrey that confusion understandable. That is working because of explicit implementations of GetEnumerator. If you are not casting to IDictionary - then you will not be able to use DictionaryEntry in foreachCheddar
@JosephHumfrey - That does not matter. It still works and a generic Dictionary<T,U> still implements IDictionary and because it does you can still use DictionaryEntry as the implementation is interface explicitly. See dotnetfiddle.Irritative
@Irritative Nobody is denying that that will work on a Dictionary<TKey, TValue>, but there is nothing in the IDictionary interface to ensure that the iterator variable will be a DictionaryEntry (see my comment above).Irritate
@Irritate - your right, I thought you were the OP (joseph), my fault.Irritative
@Irritative No worries :)Irritate
Cool, thanks for the answer and the insightful comments!Dnieper
I
8

The point you're missing is that there are no guarantees of what the type of the values will be if you iterate an IDictionary. They could be literally anything. The only guarantee is that it implements .GetEnumerator().

If you want to iterate over the contents of the IDictionary, you can iterate over its keys:

foreach (object key in myIDictionary.Keys)
{
    object value = myIDictionary[key];

    // do something with key and value
}

You can also convert your IDictionary to a Dictionary<object, object> to make foreach a bit more friendly:

var myDictionary = myIDictionary.Keys
                                .Cast<object>()
                                .ToDictionary(k => k, k => d[k]);

// kv is a KeyValuePair<object, object>
foreach (var kv in dobj)
{

}

You can even add an extension method to do this for you:

public static Dictionary<object, object> ToDictionary(this IDictionary dict)
{
    return dict.Keys.Cast<object>().ToDictionary(k => k, k => dict[k]);
}


// usage
// kv is a KeyValuePair<object, object>
foreach (var kv in myIDictionary.ToDictionary())
{
}
Irritate answered 24/3, 2017 at 15:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.