2

I have an IDictionary (not generic, so I am dealing with object's here), and I would like to get from it only the elements in that IDictionary which correspond to a specific key type K and a specific value type V. There are a billion ways to do this, but the most elegant way I have found seems to be this:

Dictionary<K, V> dict = myIDictionary.OfType<KeyValuePair<K, V>>();

This compiles fine so I am assuming this method CAN work for a dictionary (it's declared by IEnumerable) but the resulting dictionary is empty, although there are definitely KVPs in there that meet those conditions. Obviously I was assuming that KeyValuePair<K, V> is the format it is expecting, since that's what's used in enumeration over a dictionary, but is it something else? Is there something I'm missing?

Maltor
  • 553
  • 6
  • 16
  • What is the runtime type of the dictionary? – Servy Sep 06 '13 at 16:58
  • I guest the type of dictionary (implements `IDictionary`) can be found in `System.Collections.Specialized`, there are `ListDictionary`, `HybridDictionary` and `OrderedDictionary` in there. – King King Sep 06 '13 at 17:08

2 Answers2

4

A non-generic IDictionary doesn't use a KeyValue<T,U> type, so you'll never have any matches.

You would need to parse the DictionaryEntry items, and convert them:

Dictionary<K,V> dict = myIDictionary
                          .Cast<DictionaryEntry>()
                          .Where(de => de.Key is K && de.Value is V)
                          .ToDictionary(de => (K)de.Key, de => (V)de.Value);
Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
  • Thanks, I figured it would end up being a more involved LINQ query. Just curious, then: What could be a possible use case for OfType with an IDictionary then? Is there any scenario where it wouldn't return either the entire data set or nothing? – Maltor Sep 06 '13 at 17:11
  • 1
    @Maltor Not really - the enumerator will always be DictionaryEntry, since it's non generic. It's useful for other non-generic collections, though. – Reed Copsey Sep 06 '13 at 17:16
2

The OfType function does filter the list based on the specified type... but you don't have anything of the type KeyValuePair<K,V> in your base IDictionary. You've only got whatever type the non-generic IDictionary object contains (I'm not positive at the moment - maybe DictionaryEntry?). Even if it "matches" by the generic types of the pair, it's not really the same outer type.

So that function won't do what you're looking for. You need to do something with a Where statement. Something like:

var dict = myIDictionary.Where(e => e.Key is typeof(K) && e.value is typeof(V))

though that is straight pseudocode, not positive what the actual syntax is.

Edit: Looks like Reed has the full solution spelled out quite nicely.

Tim
  • 14,999
  • 1
  • 45
  • 68