Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

A Concurrent Collection: a MultiMap Generic Collection Class in C# - Part 2

, 5 Jun 2009 CPOL
MultiMap is similar to a .NET Dictionary collection type, but accepts duplicate Key,Value pairs during addition. The MultiMap collection is also a concurrent collection.
ConsoleTest.zip
ConsoleTest
bin
Release
ConsoleTest.exe
MultiMap.dll
Properties
MultiMap
bin
Release
MultiMap.dll
MultiMap.suo
Properties
MultiMapTest
bin
Release
MultiMap.dll
MultiMapTest.exe
Properties
Settings.settings
Demo.zip
Demo
MultiMap.dll
MultiMapTest.exe
MultiMap.zip
MultiMap.dll
MultiMapTest.zip
Debug
MultiMap.dll
MultiMap.pdb
MultiMapTest.exe
MultiMapTest.pdb
MultiMapTest.vshost.exe
MultiMap.dll
MultiMap.pdb
MultiMapTest.exe
MultiMapTest.pdb
MultiMapTest.vshost.exe
MultiMapTest.vshost.exe.manifest
obj
Debug
MultiMapTest.csproj.GenerateResource.Cache
MultiMapTest.exe
MultiMapTest.Form1.resources
MultiMapTest.pdb
MultiMapTest.Properties.Resources.resources
TempPE
Release
MultiMapTest.csproj.GenerateResource.Cache
MultiMapTest.exe
MultiMapTest.Form1.resources
MultiMapTest.pdb
MultiMapTest.Properties.Resources.resources
TempPE
Settings.settings
Debug
ConsoleTest.exe
ConsoleTest.pdb
ConsoleTest.vshost.exe
MultiMap.dll
MultiMap.pdb
ConsoleTest.exe
ConsoleTest.pdb
ConsoleTest.vshost.exe
ConsoleTest.vshost.exe.manifest
MultiMap.dll
MultiMap.pdb
obj
Debug
ConsoleTest.exe
ConsoleTest.pdb
TempPE
Release
ConsoleTest.exe
ConsoleTest.pdb
ResolveAssemblyReference.cache
TempPE
Debug
MultiMap.dll
MultiMap.pdb
MultiMap.dll
MultiMap.pdb
obj
Debug
MultiMap.dll
MultiMap.pdb
TempPE
Release
MultiMap.dll
MultiMap.pdb
TempPE
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Web;


namespace BK.Util
{
  
    /// <summary>
    /// A Generic Dictionary collection type that can store multiple values for the same key.
    /// </summary>
    /// <typeparam name="Key"></typeparam>
    /// <typeparam name="Value"></typeparam>
    public class MultimapBK<Key, Value> : IDisposable, IEnumerable<KeyValuePair<Key, ValueItem<Key, Value>>> where Key:IComparable<Key>
    {
        private Dictionary<Key, List<Value>> dictMultiMap;
        private List<Key> listForEnumerator;
        private Dictionary<string, ThreadDetails<Key, Value>> dictForThreadOrSession;
        private Dictionary<Key, LockDetails<Key, Value>> lockDetailsForKeys;
        
        private bool dispose;
        
        /// <summary>
        /// Construction of Multi map
        /// </summary>
        public MultimapBK()
        {
            try
            {
                Initialize();
            }
            catch(Exception ex)
            {
                throw new MultiMapBKException(ex, ex.Message);
            }
        }

        /// <summary>
        /// Gets the Enumerator
        /// </summary>
        /// <returns></returns>
        public MultimapEnum GetEnumerator()
        {
            return new MultimapEnum(this);
        }

        /// <summary>
        /// Construction copying from another Multi map
        /// </summary>
        /// <param name="DictToCopy"></param>
        public MultimapBK(ref MultimapBK<Key, Value> DictToCopy)
        {
            try
            {
                Initialize();

                if (DictToCopy != null)
                {
                    lock (DictToCopy.dictForThreadOrSession)
                    {
                        lock (dictForThreadOrSession)
                        {
                            Dictionary<Key, List<Value>>.Enumerator enumCopy = DictToCopy.dictMultiMap.GetEnumerator();

                            while (enumCopy.MoveNext())
                            {
                                List<Value> listValue = new List<Value>();
                                List<Value>.Enumerator enumList = enumCopy.Current.Value.GetEnumerator();

                                while (enumList.MoveNext())
                                {
                                    listValue.Add(enumList.Current);
                                }

                                dictMultiMap.Add(enumCopy.Current.Key, listValue);
                            }
                        }
                    }
                }
            }
            catch(Exception ex)
            {
                throw new MultiMapBKException(ex, ex.Message);   
            }
        }

        /// <summary>
        /// Adds an element to the Multi map.
        /// </summary>
        /// <param name="KeyElement"></param>
        /// <param name="ValueElement"></param>
        public void Add(Key KeyElement, Value ValueElement)
        {
            try
            {
                List<Value> listToAdd = null;

                lock (dictForThreadOrSession)
                {
                    if (dictMultiMap.TryGetValue(KeyElement, out listToAdd))
                    {
                        listToAdd.Add(ValueElement);
                    }
                    else
                    {
                        listToAdd = new List<Value>();
                        listToAdd.Add(ValueElement);
                        dictMultiMap.Add(KeyElement, listToAdd);
                        listForEnumerator.Add(KeyElement); // Added for enumerating at Order(1)
                        lockDetailsForKeys.Add(KeyElement, new LockDetails<Key, Value>(this));
                    }
                }
            }
            catch(Exception ex)
            {
                throw new MultiMapBKException(ex, ex.Message);
            }
        }

        /// <summary>
        /// Gets the first Item in the Multi map.
        /// </summary>
        /// <param name="ItemToFind"></param>
        /// <returns></returns>
        public Value GetFirstItem(Key ItemToFind)
        {
            Value retVal = default(Value);
            try
            {
                List<Value> listItems = null;

                lock (dictForThreadOrSession)
                {
                    if (dictMultiMap.TryGetValue(ItemToFind, out listItems))
                    {
                        if (listItems.Count > 0)
                        {
                            retVal = listItems[0];

                            SetFirstItemRetrieved(ItemToFind);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                throw new MultiMapBKException(ex, ex.Message);
            }

            return retVal;

        }

        /// <summary>
        /// Gets the Next Item in Multi map.  If this method is called first, it returns first item.
        /// </summary>
        /// <param name="ItemToFind"></param>
        /// <returns></returns>
        public Value GetNextItem(Key ItemToFind)
        {
            Value retVal = default(Value);

            try
            {
                lock (dictForThreadOrSession)
                {
                    List<Value> listItems = null;
                    if (dictMultiMap.TryGetValue(ItemToFind, out listItems))
                    {
                        if (listItems.Count > 0)
                        {
                            int CounterToRetrieve = GetItemToBeRetrievedForCurrentThreadOrSession(ItemToFind);

                            if (CounterToRetrieve >= listItems.Count)
                            {
                                return retVal;
                            }

                            if (CounterToRetrieve == -1)
                            {
                                CounterToRetrieve = MoveToNextItemForThreadOrSession(ItemToFind);
                            }

                            retVal = listItems[CounterToRetrieve];
                           
                            MoveToNextItemForThreadOrSession(ItemToFind);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                throw new MultiMapBKException(ex, ex.Message);
            }

            return retVal;
        }
        /// <summary>
        /// Gets the Current value in the list of values for the searched Key
        /// </summary>
        /// <param name="ItemToFind"></param>
        /// <returns></returns>
        public Value GetCurrentItem(Key ItemToFind)
        {
            Value retVal = default(Value);

            try
            {
                lock (dictForThreadOrSession)
                {
                    List<Value> listItems = null;
                    if (dictMultiMap.TryGetValue(ItemToFind, out listItems))
                    {
                        if (listItems.Count > 0)
                        {
                            int CounterToRetrieve = GetItemToBeRetrievedForCurrentThreadOrSession(ItemToFind);

                            if (CounterToRetrieve >= listItems.Count)
                            {
                                return retVal;
                            }

                            retVal = listItems[CounterToRetrieve];
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                throw new MultiMapBKException(ex, ex.Message);
            }

            return retVal;
        }

        /// <summary>
        /// Gets the Nth Item in Multi map.  
        /// </summary>
        /// <param name="ItemNumber"></param>
        /// <returns></returns>
        public KeyValuePair<Key,ValueItem<Key,Value>> GetNthItem(int ItemNumber)
        {
            KeyValuePair<Key, ValueItem<Key, Value>> retValue = default(KeyValuePair<Key, ValueItem<Key, Value>>);

            try
            {
                if (ItemNumber < 0) return retValue;

                lock (dictForThreadOrSession)
                {
                    if (ItemNumber < listForEnumerator.Count)
                    {
                        Key keyToSearchInDict = listForEnumerator[ItemNumber];

                        List<Value> listValueReturned= null;
                        if (dictMultiMap.TryGetValue(keyToSearchInDict, out listValueReturned))
                        {
                            retValue = new KeyValuePair<Key, ValueItem<Key, Value>>(keyToSearchInDict, new ValueItem<Key, Value>(this, keyToSearchInDict));
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                throw new MultiMapBKException(ex, ex.Message);
            }

            return retValue;
        }

        /// <summary>
        /// Gets the Item in Multi map based on Key passed. 
        /// </summary>
        /// <param name="KeyItem"></param>
        /// <param name="keyValuePair"></param>
        /// <returns></returns>
        internal bool GetForKey(Key KeyItem, ref KeyValuePair<Key, ValueItem<Key, Value>> keyValuePair)
        {
            keyValuePair = default(KeyValuePair<Key, ValueItem<Key, Value>>);
            bool retValue = false;

            try
            {
                lock (dictForThreadOrSession)
                {
                    List<Value> listValueReturned = null;
                    if (dictMultiMap.TryGetValue(KeyItem, out listValueReturned))
                    {
                        LockDetails<Key, Value> lockDetails = null;

                        if (lockDetailsForKeys.TryGetValue(KeyItem, out lockDetails))
                        {
                            if (lockDetails.ItemMarkedForDeleteAll)
                            {
                                if (lockDetails.IsItemVisibleToThisThread(GetThreadOrDetails().ThreadId))
                                {
                                    keyValuePair = new KeyValuePair<Key, ValueItem<Key, Value>>(KeyItem, new ValueItem<Key, Value>(this, KeyItem));
                                    retValue = true;
                                }
                                else
                                {
                                    //Key KeyItemNew = default(Key);
                                    //int StoredIndex = GetThreadOrSessionDetails().GetStoredIndex(ref KeyItemNew);
                                    //if (GetNthKey(StoredIndex, ref KeyItemNew))
                                    //{
                                    //    retValue = new KeyValuePair<Key, ValueItem<Key, Value>>(KeyItemNew, new ValueItem<Key, Value>(this, KeyItemNew));

                                    //}
                                }
                            }
                            else
                            {
                                keyValuePair = new KeyValuePair<Key, ValueItem<Key, Value>>(KeyItem, new ValueItem<Key, Value>(this, KeyItem));
                                retValue = true;
                            }

                        }

                    }
                    else
                    {
                        //Key KeyItemNew = default(Key);
                        //int StoredIndex = GetThreadOrSessionDetails().GetStoredIndex(ref KeyItemNew);
                        //if (GetNthKey(StoredIndex, ref KeyItemNew))
                        //{
                        //    retValue = new KeyValuePair<Key, ValueItem<Key, Value>>(KeyItemNew, new ValueItem<Key, Value>(this, KeyItemNew));

                        //}
                    }
                }

                
            }
            catch (Exception ex)
            {
                throw new MultiMapBKException(ex, ex.Message);
            }

            return retValue;
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="Index"></param>
        /// <param name="NthKey"></param>
        /// <returns></returns>
        public bool GetNthKey(int Index, ref Key NthKey)
        {
            bool retValue = false;
            try
            {
                if (Index < 0) return retValue;

                lock (dictForThreadOrSession)
                {
                    LockDetails<Key,Value> lockDetails = null;

                    while (Index < listForEnumerator.Count)
                    {
                        if (lockDetailsForKeys.TryGetValue(listForEnumerator[Index], out lockDetails))
                        {
                            if (lockDetails.ItemMarkedForDeleteAll)
                            {
                                    Index++;
                            }
                            else
                            {
                                retValue = true;
                                NthKey = listForEnumerator[Index];
                                break;
                            }
                        }
                        else
                        {
                            break;
                            // If control comes here then thre is a bug.
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                throw new MultiMapBKException(ex, ex.Message);
            }

            return retValue;
        }


        /// <summary>
        /// Move to next Value for the specified key
        /// </summary>
        /// <param name="ItemToFind"></param>
        /// <returns></returns>
        public bool MoveToNextItem(Key ItemToFind)
        {
            bool retVal = false;

            try
            {
                lock (dictForThreadOrSession)
                {
                    List<Value> listItems = null;
                    if (dictMultiMap.TryGetValue(ItemToFind, out listItems))
                    {
                        if (listItems.Count > 0)
                        {
                            int CounterToRetrieve = MoveToNextItemForThreadOrSession(ItemToFind);

                            if (CounterToRetrieve >= listItems.Count)
                            {
                                retVal = false;
                            }
                            else
                            {
                                retVal = true;
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                throw new MultiMapBKException(ex, ex.Message);
            }

            return retVal;
        }

        /// <summary>
        /// Move the pointer to the first item for the specified key
        /// </summary>
        /// <param name="ItemToFind"></param>
        public void ResetToFirstItem(Key ItemToFind)
        {
            try
            {
                lock (dictForThreadOrSession)
                {
                    List<Value> listItems = null;
                    if (dictMultiMap.TryGetValue(ItemToFind, out listItems))
                    {
                        
                        if (listItems.Count > 0)
                        {
                            SetFirstItemRetrieved(ItemToFind);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                throw new MultiMapBKException(ex, ex.Message);
            }

        }


        /// <summary>
        /// Iterates through all the values for the Key one by one.
        /// </summary>
        /// <param name="ItemToFind"></param>
        /// <returns></returns>
        public Value Iterate(Key ItemToFind)
        {
            return GetNextItem(ItemToFind);
        }

        /// <summary>
        /// Removes the Key and all the values for an item.
        /// </summary>
        /// <param name="KeyElement"></param>
        internal bool DeleteAll(Key KeyElement)
        {
            bool retVal = false;

            try
            {
                List<Value> listToRemove = null;

                lock (dictForThreadOrSession)
                {
                    if (dictMultiMap.TryGetValue(KeyElement, out listToRemove))
                    {
                        listToRemove.Clear();
                        dictMultiMap.Remove(KeyElement);
                        listForEnumerator.Remove(KeyElement);
                        lockDetailsForKeys.Remove(KeyElement);
                        retVal = true;
                    }
                }

            }
            catch (Exception ex)
            {
                throw new MultiMapBKException(ex, ex.Message);
            }

            return retVal;
        }

        /// <summary>
        /// Deletes one Key and one Value from the Multi map.
        /// </summary>
        /// <param name="KeyElement"></param>
        /// <param name="ValueElement"></param>
        internal bool Delete(Key KeyElement, Value ValueElement)
        {
            bool retVal = false;
            try
            {
                List<Value> listToRemove = null;

                lock (dictForThreadOrSession)
                {
                    if (dictMultiMap.TryGetValue(KeyElement, out listToRemove))
                    {
                        listToRemove.Remove(ValueElement);

                        if (listToRemove.Count == 0)
                        {
                            listToRemove = null;
                            retVal = dictMultiMap.Remove(KeyElement);
                            lockDetailsForKeys.Remove(KeyElement);   
                            listForEnumerator.Remove(KeyElement);
                        }
                    }
                }
            }
            catch(Exception ex)
            {
                throw new MultiMapBKException(ex, ex.Message);
            }

            return retVal;
        }

        /// <summary>
        /// Removes an Item from the collection.
        /// </summary>
        /// <param name="KeyToRemove"></param>

        public bool Remove(Key KeyToRemove)
        {
            return MarkThisItemForDeletion(KeyToRemove);
        }

        /// <summary>
        /// Removes an Item from the collection.  It waits for a timeout to be succesful.
        /// </summary>
        /// <param name="KeyToRemove"></param>
        /// <param name="TimeOut"></param>
        public bool Remove(Key KeyToRemove, int TimeOut)
        {
            AutoResetEvent eventToWait = null;
            bool retVal = MarkThisItemForDeletion(KeyToRemove, ref eventToWait);

            if (!retVal)
            {
                retVal = eventToWait.WaitOne(TimeOut, false);
            }

            return retVal;
        }

        /// <summary>
        /// Removes an Item, Value combination.
        /// </summary>
        /// <param name="KeyToRemove"></param>
        /// <param name="ValueToRemove"></param>
        /// <returns></returns>
        public bool Remove(Key KeyToRemove, Value ValueToRemove)
        {
            return MarkThisItemForDeletion(KeyToRemove, ValueToRemove);
        }

        /// <summary>
        /// Removes an Item, Value combination from Multimap
        /// </summary>
        /// <param name="KeyToRemove"></param>
        /// <param name="ValueToRemove"></param>
        /// <param name="TimeOut"></param>
        /// <returns></returns>
        public bool Remove(Key KeyToRemove, Value ValueToRemove, int TimeOut)
        {
            AutoResetEvent eventToWait = null;
            bool retVal = MarkThisItemForDeletion(KeyToRemove, ValueToRemove,ref eventToWait);

            if (!retVal)
            {
                retVal = eventToWait.WaitOne(TimeOut, false);
            }

            return retVal;
        }

        /// <summary>
        /// Clears all the elements in the collection.
        /// </summary>
        public void Clear()
        {
            lock (dictForThreadOrSession)
            {
                Dictionary<Key, List<Value>>.Enumerator enumDictElements = dictMultiMap.GetEnumerator();
                List<Key> listToRem = new List<Key>();

                while (enumDictElements.MoveNext())
                {
                    listToRem.Add(enumDictElements.Current.Key);
                    //enumDictElements.Current.Value.Clear();
                }

                List<Key>.Enumerator enumList = listToRem.GetEnumerator();

                while (enumList.MoveNext())
                {
                    this.MarkThisItemForDeletion(enumList.Current);
                }

                listToRem.Clear();
                dictForThreadOrSession.Clear();
                //dictMultiMap.Clear();
            }
        }

        /// <summary>
        /// Disposes all the objects stored in the collection.
        /// </summary>
        public void Dispose()
        {
            lock (dictForThreadOrSession)
            {
                if (!dispose)
                {
                    dispose = true;
                    DisposeAll();
                }
            }
        }

        /// <summary>
        /// Finalizer
        /// </summary>
        ~MultimapBK()
        {
            Dispose();
        }

        internal bool MarkThisItemForAccess(Key KeyItem)
        {
            LockDetails<Key, Value> lockDet = null;
            bool retVal = false;

            lock (dictForThreadOrSession)
            {
                if (lockDetailsForKeys.TryGetValue(KeyItem, out lockDet))
                {
                    lockDet.AddLock(KeyItem, GetThreadOrDetails());
                    retVal = true;
                }
                else
                {
                    retVal = false;
                }
            }

            return retVal;
        }

        internal void ReleaseThisItemFromAccess(Key KeyItem)
        {
            LockDetails<Key, Value> lockDet = null;

            lock (dictForThreadOrSession)
            {
                if (lockDetailsForKeys.TryGetValue(KeyItem, out lockDet))
                {
                    lockDet.RemoveLock(KeyItem, GetThreadOrDetails());
                }
            }
        }

        internal bool MarkThisItemForDeletion(Key KeyItem)
        {
            bool retVal = false;
            LockDetails<Key, Value> lockDet = null;

            if (lockDetailsForKeys.TryGetValue(KeyItem, out lockDet))
            {
                lock (dictForThreadOrSession)
                {
                    ReleaseThisItemFromAccess(KeyItem);
                    retVal = lockDet.AddKeyToBeDeleted(KeyItem);
                }
            }

            return retVal;
        }

        internal bool MarkThisItemForDeletion(Key KeyItem, Value ValueItem)
        {
            bool retVal = false;
            LockDetails<Key, Value> lockDet = null;

            if (lockDetailsForKeys.TryGetValue(KeyItem, out lockDet))
            {
                lock (dictForThreadOrSession)
                {
                    ReleaseThisItemFromAccess(KeyItem);
                    retVal = lockDet.AddValueToBeDeleted(KeyItem, ValueItem);
                }
            }
            return retVal;
        }

        internal bool MarkThisItemForDeletion(Key KeyItem, ref AutoResetEvent EventToWait)
        {
            bool retVal = false;
            LockDetails<Key, Value> lockDet = null;

            if (lockDetailsForKeys.TryGetValue(KeyItem, out lockDet))
            {
                lock (dictForThreadOrSession)
                {
                    ReleaseThisItemFromAccess(KeyItem);
                    retVal = lockDet.AddKeyToBeDeleted(KeyItem);
                    if (!retVal)
                    {
                        EventToWait = lockDet.NotifyOnDeletionComplete();
                    }
                }
            }

            return retVal;
        }

        internal bool MarkThisItemForDeletion(Key KeyItem, Value ValueItem, ref AutoResetEvent EventToWait)
        {
            bool retVal = false;
            LockDetails<Key, Value> lockDet = null;

            if (lockDetailsForKeys.TryGetValue(KeyItem, out lockDet))
            {
                lock (dictForThreadOrSession)
                {
                    ReleaseThisItemFromAccess(KeyItem);
                    retVal = lockDet.AddValueToBeDeleted(KeyItem, ValueItem);
                    if (!retVal)
                    {
                        EventToWait = lockDet.NotifyOnDeletionComplete();
                    }
                }
            }

            return retVal;
        }

        private void Initialize()
        {
            dispose = false;
            dictMultiMap = new Dictionary<Key, List<Value>>();
            dictForThreadOrSession = new Dictionary<string, ThreadDetails<Key, Value>>();
            listForEnumerator = new List<Key>();
            lockDetailsForKeys = new Dictionary<Key, LockDetails<Key, Value>>();
        }

        private void SetFirstItemRetrieved(Key keyItem)
        {
            ThreadDetails<Key, Value> threadDetails = null;

            threadDetails = GetThreadOrDetails();
            threadDetails.ResetCount();
            threadDetails.IncrementCurrentCount(keyItem);
            threadDetails.IncrementCurrentCount(keyItem);
            threadDetails.LastSearchedItem = keyItem;

        }

        private ThreadDetails<Key, Value> GetThreadOrDetails()
        {
            ThreadDetails<Key, Value> retVal = null;
            if (!dictForThreadOrSession.TryGetValue(Thread.CurrentThread.ManagedThreadId.ToString(), out retVal))
            {
                retVal = new ThreadDetails<Key, Value>(Thread.CurrentThread.ManagedThreadId.ToString(),
                                                                    default(Key),-1);
                dictForThreadOrSession.Add(Thread.CurrentThread.ManagedThreadId.ToString(), retVal);

            }

            return retVal;
        }

        private int GetItemToBeRetrievedForCurrentThreadOrSession(Key KeyItem)
        {
            return GetThreadOrDetails().GetCurrentCount(KeyItem);
        }

        private int MoveToNextItemForThreadOrSession(Key keyItem)
        {
            ThreadDetails<Key, Value> threadDetails = null;

            threadDetails = GetThreadOrDetails();
            threadDetails.IncrementCurrentCount(keyItem);
            threadDetails.LastSearchedItem = keyItem;

            return threadDetails.Counter;
        }

        private void DisposeAll()
        {
            Dictionary<Key, List<Value>>.Enumerator enumDictElements = dictMultiMap.GetEnumerator();
            IDisposable disposableObject = null;

            while (enumDictElements.MoveNext())
            {
                List<Value>.Enumerator enumEachValues = enumDictElements.Current.Value.GetEnumerator();
                while (enumEachValues.MoveNext())
                {
                    try
                    {
                        disposableObject = (IDisposable)enumEachValues.Current;
                        if (null != disposableObject)
                        {
                            disposableObject.Dispose();
                        }

                    }
                    catch (InvalidCastException)
                    { // This is not a disposable object
                    }
                    catch (Exception ex)
                    {
                        throw new MultiMapBKException(ex, ex.Message);
                    }
                }

                enumDictElements.Current.Value.Clear();
                try
                {
                    disposableObject = (IDisposable)enumDictElements.Current.Key;
                    if (null != disposableObject)
                    {
                        disposableObject.Dispose();
                    }
                }
                catch (InvalidCastException)
                {
                    // This is not a disposable object
                }
                catch (Exception ex)
                {
                    throw new MultiMapBKException(ex, ex.Message);
                }

            }

            dictMultiMap.Clear();
        }

        internal void StoreCurrentItem(Key KeyToStore, int CurrentIndex)
        {
            ThreadDetails<Key, Value> threadDetails = GetThreadOrDetails();

            threadDetails.StoreCurrentIndex(KeyToStore, CurrentIndex);


        }

        internal int GetStoredIndex(ref Key StoredKey)
        {

            ThreadDetails<Key, Value> threadDetails = GetThreadOrDetails();

            return threadDetails.GetStoredIndex(ref StoredKey);

        }

        IEnumerator<KeyValuePair<Key, ValueItem<Key, Value>>> IEnumerable<KeyValuePair<Key, ValueItem<Key, Value>>>.GetEnumerator()
        {
            return new MultimapEnum(this);
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return (System.Collections.IEnumerator)new MultimapEnum(this);
        }


        /// <summary>
        /// Enumerator class for the Multi map
        /// </summary>
        public class MultimapEnum: IEnumerator<KeyValuePair<Key, ValueItem<Key, Value>>>
        {
            private MultimapBK<Key, Value> multiMap;

            internal MultimapEnum(MultimapBK<Key, Value> MultiMapParam)
            {
                multiMap = MultiMapParam;
            }

            private KeyValuePair<Key, ValueItem<Key, Value>> GetCurrentItem(int CurrentItem)
            {
                //if (CurrentItem == -1)
                //{
                //    CurrentItem = 0; // Let's be gentle to give back first item.
                //}

                return multiMap.GetNthItem(CurrentItem);
            }

            KeyValuePair<Key, ValueItem<Key, Value>> IEnumerator<KeyValuePair<Key, ValueItem<Key, Value>>>.Current
            {
                get
                {
                    return this.Current;
                }
            }

            /// <summary>
            /// Returns Current Element
            /// </summary>
            public KeyValuePair<Key, ValueItem<Key, Value>> Current
            {
                get
                {
                    KeyValuePair<Key, ValueItem<Key, Value>> retValue = new KeyValuePair<Key, ValueItem<Key, Value>>();
                    Key CurrentKeyStored = default(Key);
                    int CurrentIndex = multiMap.GetStoredIndex(ref CurrentKeyStored);

                    if (CurrentIndex == -1)
                    {
                        // Let's be gentle and return empty;
                        return retValue;
                    }

                    multiMap.GetForKey(CurrentKeyStored, ref retValue);

                    return retValue;                    
                }
            }

            object System.Collections.IEnumerator.Current
            {
                get
                {
                    return (object) this.Current;
                }
            }

            /// <summary>
            /// Move to the next Item
            /// </summary>
            /// <returns></returns>

            public bool MoveNext()
            {
                Key KeyForIndex = default(Key);
                Key CurrentKeyStored = default(Key);
                bool retVal = false, releaseAccess = true;
                int CurrentIndex = multiMap.GetStoredIndex(ref CurrentKeyStored);
                if (CurrentIndex == -1)
                {
                    releaseAccess = false;
                    // Firt Item.  so no need to release access;
                }
                else
                {
                    KeyValuePair<Key, ValueItem<Key, Value>> keyValRet = default(KeyValuePair<Key, ValueItem<Key, Value>>);
                    if (!multiMap.GetForKey(CurrentKeyStored, ref keyValRet) )
                    {
                        CurrentIndex--;
                    }
                }
                CurrentIndex++;


                while (multiMap.GetNthKey(CurrentIndex, ref KeyForIndex))
                {
                    if (!multiMap.MarkThisItemForAccess(KeyForIndex))
                    {
                        CurrentIndex++;
                    }
                    else
                    {
                        retVal = true;
                        multiMap.StoreCurrentItem(KeyForIndex, CurrentIndex);
                        break;
                    }
                }

                if (releaseAccess)
                {
                    multiMap.ReleaseThisItemFromAccess(CurrentKeyStored);
                }
                return retVal;
            }

            /// <summary>
            /// Reset to the first Item
            /// </summary>
            public void Reset()
            {
                Key CurrentKeyStored = default(Key);
                int CurrentIndex = multiMap.GetStoredIndex(ref CurrentKeyStored);
                if (CurrentIndex != -1)
                {
                    multiMap.ReleaseThisItemFromAccess(CurrentKeyStored);
                }
                multiMap.StoreCurrentItem(default(Key), -1);

            }

            /// <summary>
            /// Dispose the object
            /// </summary>
            public void Dispose()
            {
                // Since outer class is disposing, we dont need to here.
            }


        }

    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Bharath K A
Software Developer (Senior)
United States United States
No Biography provided

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.141223.1 | Last Updated 5 Jun 2009
Article Copyright 2009 by Bharath K A
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid