tags:

views:

133

answers:

4

I have a dictionary as follows:

  IDictionary<string, string> dict;

How to create an enumerator that implements IDictionaryEnumerator (preferably using linq)?

+2  A: 

Must be missing something here, what about:

IDictionary obsoleteDict = dict as IDictionary;
if (obsoleteDict == null)
{
 //Do something here...
}
else
{
 return obsoleteDict.GetEnumerator();
}

(edit: yep, you have to cast it to the old non-generic interface)

edit2: see Pavel's comment below. A type implementing IDictionary<K,V> may or may not implement IDictionary (Dictionary<K,V> does while some implementations like WCF's MessageProperties do not) so the cast may not work.

Yann Schwartz
It returns IEnumerator<KeyValuePar<string, string>> which doesn't cast to IDictionaryEnumerator
Piotr Czapla
You have to cast your dictionary to the non generic interface IDictionary before calling GetEnumerator, and you'll get an enumerator yielding DictionaryEntry.
Jb Evain
Btw. Do you know where i can find available casts in .net. I can't find it in the msdn
Piotr Czapla
Edited answer. Well, basically my answer was wrong.
Yann Schwartz
This isn't a good general approach, because there's no guarantee that a particular implementation of `IDictionary<TKey, TValue>` also implements non-generic `IDictionary`. While `Dictionary<TKey, TValue>` implements both, in the question itself, the variable is specifically declared as `IDictionary<TKey, TValue>`, which implies that other implementations are possible.
Pavel Minaev
@Pavel Yep, you're right. LinkedDictionary<K,V> does not for instance. I'm nuking my answer.
Yann Schwartz
A: 

In most cases, this will work. Then ones where it doesn't will throw an exception.

return (IDictionaryEnumerator)dict.GetEnumerator();

At least the following BCL types return enumerators that implement IDictionaryEnumerator (these are the ones I checked):

  • Hashtable (public API enforced)
  • Dictionary<T,K> (public API enforced)
  • SortedList<T,K> (not guaranteed by the public API, but the implementation does implement it)
280Z28
Why this answer was downvoted?
Piotr Czapla
+2  A: 

I believe that IDictionaryEnumerator is only implemented by non-generic dictionary types. The generic dictionary classes expose IEnumerator.

Since generic dictionaries return strongly typed KeyValuePair items, the features of IDictionaryEnumerator seem redundant. You should try to adapt your code if possible to just use IEnumerator<KeyValuePair<K,V>>.

LBushkin
IDictionaryEnumerator is implemented by the enumerator types for most of the generic IDictionary types as well.
280Z28
Thanks for the addition Marc.
LBushkin
Oops! edited wrong post; fixing now...
Marc Gravell
+1  A: 

IDictionaryEnumerator is really the pre-generics version; you should just be able to use IEnumerator<KeyValuePair<string,string>>...

You could encapsulate, of course; this will then work even for custom implementations:

using System;
using System.Collections;
using System.Collections.Generic;
static class Program
{
    class MyEnumerator<TKey,TValue> : IDictionaryEnumerator, IDisposable
    {
        readonly IEnumerator<KeyValuePair<TKey, TValue>> impl;
        public void Dispose() { impl.Dispose(); }
        public MyEnumerator(IDictionary<TKey, TValue> value)
        {
            this.impl = value.GetEnumerator();
        }
        public void Reset() { impl.Reset(); }
        public bool MoveNext() { return impl.MoveNext(); }
        public DictionaryEntry Entry { get { var pair = impl.Current;
            return new DictionaryEntry(pair.Key, pair.Value);} }
        public object Key { get { return impl.Current.Key; } }
        public object Value { get { return impl.Current.Value; } }
        public object Current {get {return Entry;}}
    }
    static IDictionaryEnumerator GetBasicEnumerator<TKey,TValue>(
        this IDictionary<TKey, TValue> data)
    {
        return new MyEnumerator<TKey, TValue>(data);
    }
    static void Main()
    {
        IDictionary<int, string> data = new Dictionary<int, string>()
        {
            {1,"abc"}, {2,"def"}
        };
        IDictionaryEnumerator basic;
        using ((basic = data.GetBasicEnumerator()) as IDisposable)
        {
            while (basic.MoveNext())
            {
                Console.WriteLine(basic.Key + "=" + basic.Value);
            }
        }
    }
}
Marc Gravell
You should use `as` to check for an existing implementation of `IDictionaryEnumerator`. If it returns null, *then* wrap the `IEnumerator<KeyValuePair<TKey, TValue>>`.
280Z28