21

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!

Joseph Humfrey
  • 2,974
  • 2
  • 23
  • 34
  • 2
    `I think x is an object` Why don't you check what it actually is, rather than just guessing. – Servy Mar 24 '17 at 15:41
  • @Servy x IS an object, everything is an object in OOP – Bernard Walters Mar 24 '17 at 15:43
  • @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. – JLRishe Mar 24 '17 at 15:45
  • 1
    @BernardWalters It's a type that's derived from an object. It's convertible to "object". The type of `x` is not "object" though. – Servy Mar 24 '17 at 15:48
  • 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.) – Joseph Humfrey Mar 24 '17 at 15:50
  • 1
    @JosephHumfrey You can look at the documentation for the type if you want to find out what the items are. – Servy Mar 24 '17 at 15:51
  • Possible duplicate of [What is the best way to iterate over a Dictionary in C#?](http://stackoverflow.com/questions/141088/what-is-the-best-way-to-iterate-over-a-dictionary-in-c) – Igor Mar 24 '17 at 15:52
  • _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. – TaW Mar 24 '17 at 15:55
  • 1
    @Servy - 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. – Joseph Humfrey Mar 24 '17 at 15:57
  • 1
    @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. – Servy Mar 24 '17 at 15:58

2 Answers2

26

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.

Lanorkin
  • 7,310
  • 2
  • 42
  • 60
  • 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. – JLRishe Mar 24 '17 at 16:05
  • 2
    I guess my point of confusion is the fact that an `IDictionary`'s enumerator uses `DictionaryEntry`, and yet a concrete `Dictionary` (for example), would use a `KeyValuePair` (which isn't related to a `DictionaryEntry`). So the behaviour actually depends on the specific casting of the dictionary variable that you iterate. – Joseph Humfrey Mar 24 '17 at 16:05
  • @JLRishe yes, indeed – Lanorkin Mar 24 '17 at 16:08
  • 2
    @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 `foreach` – Lanorkin Mar 24 '17 at 16:11
  • @JosephHumfrey - That does not matter. It still works and a generic `Dictionary` still implements `IDictionary` and because it does you can still use `DictionaryEntry` as the implementation is interface explicitly. See [dotnetfiddle](https://dotnetfiddle.net/vcRPPw). – Igor Mar 24 '17 at 16:18
  • @Igor Nobody is denying that that will work on a `Dictionary`, but there is nothing in the `IDictionary` interface to ensure that the iterator variable will be a `DictionaryEntry` (see my comment above). – JLRishe Mar 24 '17 at 16:23
  • @JLRishe - your right, I thought you were the OP (joseph), my fault. – Igor Mar 24 '17 at 16:42
  • @Igor No worries :) – JLRishe Mar 24 '17 at 16:44
  • Cool, thanks for the answer and the insightful comments! – Joseph Humfrey Mar 24 '17 at 17:30
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())
{
}
JLRishe
  • 99,490
  • 19
  • 131
  • 169