/EmlenMud/BrainTechLLC.ThreadSafeObjects/ThreadSafeObjects/ThreadSafeLookupNonRef.cs
C# | 344 lines | 277 code | 55 blank | 12 comment | 23 complexity | 86f5394060457442e38626af07a14f39 MD5 | raw file
- // Original author contact info: Owen Emlen (owene_1998@yahoo.com)
- // Note: other individuals may also have contributed to this code
- // Project hosted on CodePlex.com as of 1/10/2009 at http://www.codeplex.com/EmlenMud
- using System;
- using System.Xml.Serialization;
- using System.Runtime.Serialization;
- using System.Linq;
- using System.Collections.Generic;
- using System.Collections.Specialized;
- using System.Collections;
- using System.ComponentModel;
- #if USE_HYPER
- using Hyper.ComponentModel;
- #endif
-
- namespace BrainTechLLC.ThreadSafeObjects
- {
- /// <summary>
- /// Thread-safe lookup allows multiple threads to look up items by key, add items,
- /// and remove items in a thread-safe manner
- /// </summary>
- /// <typeparam name="TListType"></typeparam>
- /// <typeparam name="TIndex"></typeparam>
- #if NO_SILVERLIGHT
- [TypeDescriptionProvider(typeof(HyperTypeDescriptionProvider))]
- #endif
- [Serializable]
- [DataContract]
- public class ThreadSafeLookupNonRef<TIndex, TListType> : Lockable, INotifyCollectionChanged,
- IDictionary<TIndex, TListType>, IMultipleItems<TListType>, ISupportsCount
- {
- public override string ToString()
- {
- return Count.ToString();
- }
-
- // add track changes
- [NonSerialized, XmlIgnore]
- public bool Modified;
-
- [DataMember]
- public Dictionary<TIndex, TListType> Lookup = new Dictionary<TIndex, TListType>();
-
- #if NO_SILVERLIGHT
- [EditorBrowsable(EditorBrowsableState.Always)]
- #endif
- public TListType[] ArrayOfItems { get { return AllItems.ToArray(); } }
-
- #if NO_SILVERLIGHT
- [EditorBrowsable(EditorBrowsableState.Always)]
- #endif
- public int Count { get { return Lookup.Count; } }
-
- public bool ContainsKey(TIndex key) { return Lookup.ContainsKey(key); }
- public bool TryGetValue(TIndex key, out TListType items) { return Lookup.TryGetValue(key, out items); }
-
- public bool Remove(KeyValuePair<TIndex, TListType> kvp)
- {
- return Remove(kvp.Key, kvp.Value);
- }
-
- #if NO_SILVERLIGHT
- [EditorBrowsable(EditorBrowsableState.Never), Browsable(false)]
- #endif
- public List<TListType> AllItems
- {
- get
- {
- List<TListType> items = new List<TListType>(Lookup.Count);
-
- AquireLock();
- {
- foreach (KeyValuePair<TIndex, TListType> kvp in Lookup)
- items.Add(kvp.Value);
- }
- ReleaseLock();
-
- return items;
- }
- }
-
- public bool AddMultiple(IEnumerable<TIndex> keys, IList<TListType> values)
- {
- List<TListType> addedItems = null;
- bool added = false;
- int n = 0;
-
- if (CollectionChanged != null)
- addedItems = new List<TListType>();
-
- AquireLock();
- {
- foreach (TIndex key in keys)
- {
- if (!Lookup.ContainsKey(key))
- {
- Lookup.Add(key, values[n]);
- if (addedItems != null) addedItems.Add(values[n]);
- Modified = true;
- added = true;
- }
- n++;
- }
- }
- ReleaseLock();
-
- if (added)
- OnNotifyCollectionChanged(NotifyCollectionChangedAction.Add, addedItems);
-
- return added;
- }
-
- public bool Add(TIndex key, TListType item)
- {
- bool found = true;
-
- AquireLock();
- {
- if (!Lookup.ContainsKey(key))
- {
- Lookup.Add(key, item);
- Modified = true;
- found = false;
- }
- }
- ReleaseLock();
-
- if (!found)
- OnNotifyCollectionChanged(NotifyCollectionChangedAction.Add, item);
-
- return !found;
- }
-
- public void AddOrSet(TIndex key, TListType item)
- {
- if (Lookup.ContainsKey(key))
- {
- TListType old = default(TListType);
- Lookup.TryGetValue(key, out old);
- if (!old.Equals(item))
- {
- Lookup[key] = item;
- Modified = true;
-
- if (CollectionChanged != null)
- OnNotifyCollectionChanged(NotifyCollectionChangedAction.Replace, new List<TListType>() { old, item });
- }
- }
- else
- {
- Add(key, item);
- OnNotifyCollectionChanged(NotifyCollectionChangedAction.Add, item);
- }
- }
-
- public TListType this[TIndex key]
- {
- get
- {
- TListType item;
-
- // Not totally safe for lookups that frequently add/remove items.
- // For thread safety, surround the following line with AquireLock(); / ReleaseLock();
- if (!Lookup.TryGetValue(key, out item)) item = default(TListType);
-
- return item;
- }
- set
- {
- AddOrSet(key, value);
- }
- }
-
- public bool Remove(TIndex key, TListType item)
- {
- return Remove(key);
- }
-
- public bool Remove(TIndex key)
- {
- bool removed = false;
-
- if (!Lookup.ContainsKey(key))
- return false;
-
- TListType item = default(TListType);
- AquireLock();
- {
- if (Lookup.TryGetValue(key, out item))
- {
- Lookup.Remove(key);
- Modified = true;
- removed = true;
- }
- }
- ReleaseLock();
-
- if (removed)
- OnNotifyCollectionChanged(NotifyCollectionChangedAction.Remove, item);
-
- return removed;
- }
-
- public void Clear()
- {
- IList<TListType> items = null;
-
- if (CollectionChanged != null)
- items = new List<TListType>(AllItems);
-
- AquireLock();
- {
- Lookup.Clear();
- Modified = true;
- }
- ReleaseLock();
-
- OnNotifyCollectionChanged(NotifyCollectionChangedAction.Reset, items);
- }
-
- System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
- {
- return Lookup.GetEnumerator();
- }
-
- public IEnumerator<KeyValuePair<TIndex, TListType>> GetEnumerator()
- {
- return Lookup.GetEnumerator();
- }
-
- #if NO_SILVERLIGHT
- [EditorBrowsable(EditorBrowsableState.Never), Browsable(false)]
- #endif
- public bool IsReadOnly { get { return false; } }
-
- #if NO_SILVERLIGHT
- [EditorBrowsable(EditorBrowsableState.Never), Browsable(false)]
- #endif
- public List<TIndex> Keys
- {
- get
- {
- List<TIndex> items = new List<TIndex>(Lookup.Count);
- AquireLock(); { Lookup.ForEach(kvp => items.Add(kvp.Key)); } ReleaseLock();
- return items;
- }
- }
-
- public void OnNotifyCollectionChanged(NotifyCollectionChangedAction action, IList<TListType> changedItems)
- {
- if (CollectionChanged != null)
- {
- switch (action)
- {
- case NotifyCollectionChangedAction.Add:
- CollectionChanged(this, new NotifyCollectionChangedEventArgsEx<TListType>(action, changedItems));
- break;
- case NotifyCollectionChangedAction.Remove:
- CollectionChanged(this, new NotifyCollectionChangedEventArgsEx<TListType>(action, changedItems));
- break;
- case NotifyCollectionChangedAction.Replace:
- CollectionChanged(this, new NotifyCollectionChangedEventArgsEx<TListType>(action, changedItems[0], changedItems[1]));
- break;
- case NotifyCollectionChangedAction.Reset:
- CollectionChanged(this, new NotifyCollectionChangedEventArgsEx<TListType>(action));
- break;
- }
- }
- }
-
- public void OnNotifyCollectionChanged(NotifyCollectionChangedAction action, TListType changedItem)
- {
- if (CollectionChanged != null)
- OnNotifyCollectionChanged(action, new List<TListType>() { changedItem });
- }
-
- #region INotifyCollectionChanged Members
-
- #if NO_SILVERLIGHT
- [field: NonSerialized]
- public event NotifyCollectionChangedEventHandler CollectionChanged;
- #else
- [field: NonSerialized]
- public event EventHandler<NotifyCollectionChangedEventArgsEx<TListType>> CollectionChanged;
- #endif
-
- #endregion
-
- #region IDictionary<TIndex,TListType> Members
-
- void IDictionary<TIndex, TListType>.Add(TIndex key, TListType value)
- {
- this.Add(key, value);
- }
-
- #if NO_SILVERLIGHT
- [EditorBrowsable(EditorBrowsableState.Never), Browsable(false)]
- #endif
- ICollection<TIndex> IDictionary<TIndex, TListType>.Keys
- {
- get { return Lookup.Keys; }
- }
-
- #if NO_SILVERLIGHT
- [EditorBrowsable(EditorBrowsableState.Never), Browsable(false)]
- #endif
- public ICollection<TListType> Values
- {
- get { return Lookup.Values; }
- }
-
- #endregion
-
- #region ICollection<KeyValuePair<TIndex,TListType>> Members
-
- public void Add(KeyValuePair<TIndex, TListType> item)
- {
- Add(item.Key, item.Value);
- }
-
- public bool Contains(KeyValuePair<TIndex, TListType> item)
- {
- return Lookup.Contains(item);
- }
-
- #endregion
-
- #region ICollection<KeyValuePair<TIndex,TListType>> Members
-
- public void CopyTo(KeyValuePair<TIndex, TListType>[] array, int arrayIndex)
- {
- AquireLock();
- {
- foreach (KeyValuePair<TIndex, TListType> item in Lookup)
- {
- array[arrayIndex++] = item;
- }
- }
- ReleaseLock();
- }
-
- #endregion
- }
- }