view Implab/Components/ComponentContainer.cs @ 187:dd4a3590f9c6 ref20160224

Reworked cancelation handling, if the cancel handler isn't specified the OperationCanceledException will be handled by the error handler Any unhandled OperationCanceledException will cause the promise cancelation
author cin
date Tue, 19 Apr 2016 17:35:20 +0300
parents b933ec88446e
children 1e082fb67a46
line wrap: on
line source

using System;
using System.Collections.Generic;
using System.Linq;

namespace Implab.Components {
    /// <summary>
    /// Component container, used to store track components in multi-threaded environmment.
    /// </summary>
    /// <remarks>Instanses of this class are thread safe.</remarks>
    public class ComponentContainer<T> : Disposable, ICollection<T> {
        readonly HashSet<T> m_components = new HashSet<T>();

        /// <summary>
        /// Removes currently stored compoenents from the container and disposes them if possible.
        /// </summary>
        /// <remarks>
        /// A new components may be added before this method completes.
        /// </remarks>
        public void Clear() {
            T[] removed;

            lock (m_components) {
                removed = new T[m_components.Count];
                m_components.CopyTo(removed);
                m_components.Clear();
            }

            foreach (var item in removed.OfType<IDisposable>())
                item.Dispose();
        }

        /// <summary>
        /// Checks whether the specified item in the collection.
        /// </summary>
        /// <param name="item">The item to check.</param>
        public bool Contains(T item) {
            lock (m_components)
                return m_components.Contains(item);
        }

        /// <summary>
        /// Copies currently stored components to the specified array.
        /// </summary>
        /// <param name="array">A destination array for components.</param>
        /// <param name="arrayIndex">A starting index in the destination array.</param>
        public void CopyTo(T[] array, int arrayIndex) {
            lock (m_components)
                m_components.CopyTo(array, arrayIndex);
        }

        /// <summary>
        /// Remove the specified item from the collection.
        /// </summary>
        /// <param name="item">The item to remove.</param>
        public bool Remove(T item) {
            lock (m_components)
                return m_components.Remove(item);
        }

        /// <summary>
        /// Gets the count of components in the collection.
        /// </summary>
        public int Count {
            get {
                lock (m_components)
                    return m_components.Count;
            }
        }

        /// <summary>
        /// Gets a value indicating whether this instance is read only.
        /// </summary>
        /// <remarks>
        /// Always false.
        /// </remarks>
        public bool IsReadOnly {
            get {
                return false;
            }
        }

        /// <summary>
        /// Gets the enumerator for components in the collection.
        /// </summary>
        /// <returns>The enumerator.</returns>
        public IEnumerator<T> GetEnumerator() {
            T[] items;
            lock (m_components) {
                items = new T[m_components.Count];
                m_components.CopyTo(items);
                return (IEnumerator<T>)items.GetEnumerator();
            }
        }

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

        /// <summary>
        /// Add the specified item to the collection.
        /// </summary>
        /// <param name="item">The item to add.</param>
        /// <remarks>
        /// If the collection is alredy disposed, the item isn't added to the collection and disposed if possible.
        /// </remarks>
        public void Add(T item) {
            Safe.ArgumentNotNull(item, "item");

            lock (m_components) {
                if (IsDisposed)
                    Safe.Dispose(item);
                else
                    m_components.Add(item);
            }
        }

        /// <summary>
        /// Disposes the components stored in the collection.
        /// </summary>
        /// <param name="disposing">If set to <c>true</c> the collection is disposing.</param>
        protected override void Dispose(bool disposing) {
            base.Dispose(disposing);
            Clear();
        }
    }
}