using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Collections; using Esiur.Engine; using System.Reflection; namespace Esiur.Data { public class AutoList : IEnumerable { private readonly object syncRoot = new object(); private List list = new List(); public delegate void Modified(ST sender, int index, T oldValue, T newValue); public delegate void Added(ST sender, T value); public delegate void Removed(ST sender, T value); public delegate void Cleared(ST sender); public event Modified OnModified; public event Removed OnRemoved; public event Cleared OnCleared; public event Added OnAdd; ST state; bool removableList; /* IOrderedEnumerable OrderBy(Func keySelector) { return list.OrderBy(keySelector); } */ public void Sort() { list.Sort(); } public void Sort(IComparer comparer) { list.Sort(comparer); } public IEnumerable Where(Func predicate) { return list.Where(predicate); } /// /// Convert AutoList to array /// /// Array public T[] ToArray() { // list.OrderBy() return list.ToArray(); } /// /// Create a new instance of AutoList /// /// State object to be included when an event is raised. public AutoList(ST state) { this.state = state; #if NETSTANDARD1_5 removableList = (typeof(IDestructible).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo())); #else removableList = (typeof(IDestructible).IsAssignableFrom(typeof(T))); #endif } /// /// Create a new instance of AutoList /// /// Populate the list with items /// public AutoList(T[] values) { #if NETSTANDARD1_5 removableList = (typeof(IDestructible).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo())); #else removableList = (typeof(IDestructible).IsAssignableFrom(typeof(T))); #endif AddRange(values); } /// /// Synchronization lock of the list /// public object SyncRoot { get { return syncRoot; } } /// /// First item in the list /// public T First() { return list.First(); } /// /// Get an item at a specified index /// public T this[int index] { get { return list[index]; } set { var oldValue = list[index]; if (removableList) { if (oldValue != null) ((IDestructible)oldValue).OnDestroy -= ItemDestroyed; if (value != null) ((IDestructible)value).OnDestroy += ItemDestroyed; } lock (syncRoot) list[index] = value; OnModified?.Invoke(state, index, oldValue, value); } } /// /// Add item to the list /// public void Add(T value) { if (removableList) if (value != null) ((IDestructible)value).OnDestroy += ItemDestroyed; lock (syncRoot) list.Add(value); OnAdd?.Invoke(state, value); } /// /// Add an array of items to the list /// public void AddRange(T[] values) { foreach (var v in values) Add(v); } private void ItemDestroyed(object sender) { Remove((T)sender); } public IEnumerator GetEnumerator() { return list.GetEnumerator(); } /// /// Clear the list /// public void Clear() { if (removableList) foreach(IDestructible v in list) if (v!=null) v.OnDestroy -= ItemDestroyed; lock (syncRoot) list.Clear(); OnCleared?.Invoke(state); } /// /// Remove an item from the list /// Item to remove /// public void Remove(T value) { if (!list.Contains(value)) return; if (removableList) if (value != null) ((IDestructible)value).OnDestroy -= ItemDestroyed; lock (syncRoot) list.Remove(value); OnRemoved?.Invoke(state, value); } /// /// Number of items in the list /// public int Count { get { return list.Count; } } /// /// Check if an item exists in the list /// /// Item to check if exists public bool Contains(T value) { return list.Contains(value); } /// /// Check if any item of the given array is in the list /// /// Array of items public bool ContainsAny(T[] values) { foreach (var v in values) if (list.Contains(v)) return true; return false; } /// /// Check if any item of the given list is in the list /// /// List of items public bool ContainsAny(AutoList values) { foreach (var v in values) if (list.Contains((T)v)) return true; return false; } } }