//----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // // // A list with locking semantics so it can be used cross-thread. // //----------------------------------------------------------------------- namespace Microsoft.Kinect.Toolkit { using System; using System.Collections; using System.Collections.Generic; /// /// IList implementation with locking on all operations. /// /// Type of generic IList to implement. public sealed class ThreadSafeCollection : IList { /// /// Lock object to use for all operations. /// private readonly object lockObject; /// /// Wrapped collection object. /// private readonly List list = new List(); /// /// Initializes a new instance of the ThreadSafeCollection class with a new lock. /// public ThreadSafeCollection() : this(new object()) { } /// /// Initializes a new instance of the ThreadSafeCollection class with an existing new lock. /// /// Existing lock to use for this collection. public ThreadSafeCollection(object existingLock) { this.lockObject = existingLock; } /// /// Gets the number of elements actually contained in the ThreadSafeCollection<T>. /// public int Count { get { lock (this.lockObject) { return list.Count; } } } /// /// Gets a value indicating whether the collection is read only. Returns true. /// public bool IsReadOnly { get { lock (this.lockObject) { return false; } } } /// /// Gets or sets the element at the specified index. /// /// The zero-based index of the element to get or set. /// The element at the specified index. public T this[int index] { get { lock (this.lockObject) { return list[index]; } } set { lock (this.lockObject) { list[index] = value; } } } /// /// Adds an object to the end of the ThreadSafeCollection<T>. /// /// /// The object to be added to the end of the ThreadSafeCollection<T>. /// The value can be null for reference types. /// public void Add(T item) { lock (this.lockObject) { list.Add(item); } } /// /// Removes all elements from the ThreadSafeCollection<T>. /// public void Clear() { lock (this.lockObject) { list.Clear(); } } /// /// Determines whether an element is in the ThreadSafeCollection<T>. /// /// /// The object to locate in the ThreadSafeCollection<T>. The value /// can be null for reference types. /// /// /// true if item is found in the ThreadSafeCollection<T>; otherwise, /// false. /// public bool Contains(T item) { lock (this.lockObject) { return list.Contains(item); } } /// /// Copies the entire ThreadSafeCollection<T> to a compatible one-dimensional /// array, starting at the beginning of the target array. /// /// /// The one-dimensional System.Array that is the destination of the elements /// copied from ThreadSafeCollection<T>. The System.Array must have /// zero-based indexing. /// /// /// The zero-based index in array at which copying begins. /// /// Array is null. /// ArrayIndex is less than 0. /// /// The number of elements in the source ThreadSafeCollection<T> is /// greater than the available space from arrayIndex to the end of the destination /// array. /// public void CopyTo(T[] array, int arrayIndex) { lock (this.lockObject) { list.CopyTo(array, arrayIndex); } } /// /// Copies the entire ThreadSafeCollection<Tgt; to a compatible one-dimensional /// array, starting at the beginning of the target array. /// /// /// The one-dimensional System.Array that is the destination of the elements /// copied from System.Collections.Generic.List<Tgt;. The System.Array must have /// zero-based indexing. /// /// Array is null. /// /// The number of elements in the source ThreadSafeCollection<Tgt; is /// greater than the number of elements that the destination array can contain. /// public void CopyTo(T[] array) { lock (this.lockObject) { list.CopyTo(array); } } /// /// Adds the elements of the specified collection to the end of the ThreadSafeCollection<T>. /// /// /// The collection whose elements should be added to the end of the ThreadSafeCollection<T>. /// The collection itself cannot be null, but it can contain elements that are /// null, if type T is a reference type. /// /// Collection is null. public void AddRange(IEnumerable collection) { lock (this.lockObject) { list.AddRange(collection); } } /// /// Searches for the specified object and returns the zero-based index of the /// first occurrence within the entire ThreadSafeCollection<T>. /// /// /// The object to locate in the ThreadSafeCollection<T>. The value /// can be null for reference types. /// /// /// The zero-based index of the first occurrence of item within the entire ThreadSafeCollection<T>, /// if found; otherwise, –1. /// public int IndexOf(T item) { lock (this.lockObject) { return list.IndexOf(item); } } /// /// Inserts an element into the ThreadSafeCollection<T> at the specified /// index. /// /// /// The zero-based index at which item should be inserted. /// /// /// The object to insert. The value can be null for reference types. /// /// Index is less than 0.-or-index is greater than ThreadSafeCollection<T>.Count. public void Insert(int index, T item) { lock (this.lockObject) { list.Insert(index, item); } } /// /// Removes the element at the specified index of the ThreadSafeCollection<T>. /// /// The zero-based index of the element to remove. /// Index is less than 0.-or-index is equal to or greater than ThreadSafeCollection<T>.Count. public void RemoveAt(int index) { lock (this.lockObject) { list.RemoveAt(index); } } /// /// Removes the first occurrence of a specific object from the ThreadSafeCollection<T>. /// /// /// The object to remove from the ThreadSafeCollection<T>. The value /// can be null for reference types. /// /// /// true if item is successfully removed; otherwise, false. This method also /// returns false if item was not found in the ThreadSafeCollection<T>. /// public bool Remove(T item) { lock (this.lockObject) { return list.Remove(item); } } /// /// Returns an enumerator that iterates through the ThreadSafeCollection<T>. /// /// This enumerator is a SNAPSHOT of the collection. Keep this in mind when using this enumerator. /// A ThreadSafeCollection<T>.Enumerator for the ThreadSafeCollection<T>. IEnumerator IEnumerable.GetEnumerator() { lock (this.lockObject) { return NewEnumerator(); } } /// /// Returns an enumerator that iterates through the ThreadSafeCollection<T>. /// /// This enumerator is a SNAPSHOT of the collection. Keep this in mind when using this enumerator. /// A ThreadSafeCollection<T>.Enumerator for the ThreadSafeCollection<T>. IEnumerator IEnumerable.GetEnumerator() { lock (this.lockObject) { return NewEnumerator(); } } /// /// Returns an enumerator that iterates through the ThreadSafeCollection<T>. /// /// This support function exists to satisfy code quality warning CA2000. Otherwise, it would be in-line. /// A ThreadSafeCollection<T>.Enumerator for the ThreadSafeCollection<T>. private IEnumerator NewEnumerator() { return new ThreadSafeEnumerator(this); } /// /// Provides a SNAPSHOT enumerator of the collection. Keep this in mind when using this enumerator. /// private class ThreadSafeEnumerator : IEnumerator { /// /// Snapshot to enumerate. /// private readonly ThreadSafeCollection collection; /// /// Internal enumerator of the snapshot. /// private readonly IEnumerator enumerator; /// /// Initializes a new instance of the ThreadSafeEnumerator class, creating a snapshot of the given collection. /// /// List to snapshot. public ThreadSafeEnumerator(ThreadSafeCollection collection) { lock (collection.lockObject) { // Make snapshot of passed in collection. this.collection = new ThreadSafeCollection(); this.collection.AddRange(collection); // Wrapped enumerator. enumerator = this.collection.list.GetEnumerator(); } } /// /// Gets the element in the collection at the current position of the enumerator. /// /// The element in the collection at the current position of the enumerator. public T Current { get { lock (this.collection.lockObject) { return enumerator.Current; } } } /// /// Gets the element in the collection at the current position of the enumerator. /// /// The element in the collection at the current position of the enumerator. object IEnumerator.Current { get { lock (this.collection.lockObject) { return enumerator.Current; } } } /// /// Disposes the underlying enumerator. Does not set collection or enumerator to null so calls will still /// proxy to the disposed instance (and throw the proper exception). /// public void Dispose() { lock (this.collection.lockObject) { enumerator.Dispose(); } } /// /// Advances the enumerator to the next element of the collection. /// /// /// true if the enumerator was successfully advanced to the next element; false /// if the enumerator has passed the end of the collection. /// /// The collection was modified after the enumerator was created. public bool MoveNext() { lock (this.collection.lockObject) { return enumerator.MoveNext(); } } /// /// Sets the enumerator to its initial position, which is before the first element /// in the collection. /// /// The collection was modified after the enumerator was created. public void Reset() { lock (this.collection.lockObject) { enumerator.Reset(); } } } } }