using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Threading; using PhoenixLib.Logging; namespace WingsEmu.Core.Generics; public class ThreadSafeList : IEnumerable, IDisposable { #region Instantiation /// /// Creates a new ThreadSafeList object. /// public ThreadSafeList() { _items = new List(); _lock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); } #endregion #region Properties /// /// Gets the number of elements contained in the . /// public int Count { get { if (!_disposed) { _lock.EnterReadLock(); try { return _items.Count; } finally { _lock.ExitReadLock(); } } return 0; } } #endregion public IEnumerator GetEnumerator() { _lock.EnterReadLock(); try { return _items.GetEnumerator(); } finally { if (_lock.IsReadLockHeld) { _lock.ExitReadLock(); } } } IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); ~ThreadSafeList() => Dispose(false); #region Members /// /// private collection to store _items. /// private readonly List _items; /// /// Used to synchronize access to _items list. /// private readonly ReaderWriterLockSlim _lock; private bool _disposed; #endregion #region Methods /// /// Adds an object to the end of the . /// /// public void Add(T value) { if (!_disposed) { _lock.EnterWriteLock(); try { _items.Add(value); } finally { _lock.ExitWriteLock(); } } } /// /// Adds the elements of the specified collection to the end of the . /// /// public void AddRange(List value) { if (!_disposed) { _lock.EnterWriteLock(); try { _items.AddRange(value); } finally { _lock.ExitWriteLock(); } } } /// /// Determines whether all elements of a sequence satisfy a condition. /// /// /// True; if elements satisfy the condition public bool All(Func predicate) { if (!_disposed) { _lock.EnterReadLock(); try { return _items.All(predicate); } finally { _lock.ExitReadLock(); } } return false; } /// /// Determines whether any element of a sequence satisfies a condition. /// /// /// /// /// public bool Any(Func predicate) { if (!_disposed) { _lock.EnterReadLock(); try { return _items.Any(predicate); } finally { _lock.ExitReadLock(); } } return false; } /// /// Removes all elements from the . /// public void Clear() { if (!_disposed) { _lock.EnterWriteLock(); try { _items.Clear(); } finally { _lock.ExitWriteLock(); } } } /// /// Copies the entire to a compatible one-dimensional array, starting at the /// beginning of the target array. /// /// public void CopyTo(T[] grpmembers) { if (!_disposed) { _lock.EnterReadLock(); try { _items.CopyTo(grpmembers); } finally { _lock.ExitReadLock(); } } } /// /// Returns a number that represents how many elements in the specified sequence satisfy a condition. /// /// /// number of found elements public int CountLinq(Func predicate) { if (!_disposed) { _lock.EnterReadLock(); try { return _items.Count(predicate); } finally { _lock.ExitReadLock(); } } return 0; } /// /// Disposes the current object. /// public void Dispose() { if (!_disposed) { _disposed = true; Dispose(true); GC.SuppressFinalize(this); } } /// /// Returns the element at given index /// /// /// object public T ElementAt(int v) { if (_disposed) { return default; } _lock.EnterReadLock(); try { return _items.ElementAt(v); } catch (Exception ex) { Log.Error("ElementAt", ex); } finally { _lock.ExitReadLock(); } return default; } /// /// Searches for an element that matches the conditions defined by the specified predicate, /// and returns the first occurrence within the entire . /// /// /// object public T Find(Predicate predicate) { if (!_disposed) { _lock.EnterReadLock(); try { return _items.Find(predicate); } finally { _lock.ExitReadLock(); } } return default; } /// /// Searches for an element that matches the conditions defined by the specified predicate, /// and returns the first occurrence within the entire . /// /// object public T FirstOrDefault() { if (!_disposed) { _lock.EnterReadLock(); try { return _items.FirstOrDefault(); } finally { _lock.ExitReadLock(); } } return default; } /// /// Performs the specified action on each element of the . /// /// public void ForEach(Action action) { if (!_disposed) { _lock.EnterReadLock(); try { _items.ForEach(action); } finally { _lock.ExitReadLock(); } } } /// /// returns a list of all objects in current thread safe generic list /// /// /// /// public List GetAllItems() { if (!_disposed) { _lock.EnterReadLock(); try { return new List(_items); } finally { _lock.ExitReadLock(); } } return new List(); } /// /// Returns the last element of a sequence that satisfies a condition or a default value if /// no such element is found. /// /// /// object public T LastOrDefault(Func predicate) { if (!_disposed) { _lock.EnterReadLock(); try { return _items.LastOrDefault(predicate); } finally { _lock.ExitReadLock(); } } return default; } /// /// Removes the first occurrence of a specific object from the . /// /// public void Remove(T match) { if (!_disposed) { _lock.EnterWriteLock(); try { _items.Remove(match); } finally { _lock.ExitWriteLock(); } } } /// /// Removes all the elements that match the conditions defined by the specified predicate. /// /// public void RemoveAll(Predicate match) { if (!_disposed) { _lock.EnterWriteLock(); try { _items.RemoveAll(match); } finally { _lock.ExitWriteLock(); } } } /// /// Returns the only element of a sequence that satisfies a specified condition, and throws /// an exception if more than one such element exists. /// /// /// object public T Single(Func predicate) { if (!_disposed) { _lock.EnterReadLock(); try { return _items.Single(predicate); } finally { _lock.ExitReadLock(); } } return default; } /// /// Returns the only element of a sequence that satisfies a specified condition or a default /// value if no such element exists; this method throws an exception if more than one element /// satisfies the condition. /// /// /// object /// public T SingleOrDefault(Func predicate) { if (!_disposed) { _lock.EnterReadLock(); try { return _items.SingleOrDefault(predicate); } finally { _lock.ExitReadLock(); } } return default; } /// /// Returns a number that represents how many elements in the specified sequence satisfy a condition. /// /// /// number of found elements public int Sum(Func selector) { if (_disposed) { return 0; } _lock.EnterReadLock(); try { return _items.Sum(selector); } finally { _lock.ExitReadLock(); } return 0; } /// /// Returns a number that represents how many elements in the specified sequence satisfy a condition. /// /// /// int? number of found elements public int? Sum(Func selector) { if (!_disposed) { _lock.EnterReadLock(); try { return _items.Sum(selector); } finally { _lock.ExitReadLock(); } } return 0; } /// /// Returns a number that represents how many elements in the specified sequence satisfy a condition. /// /// /// number of found elements public long Sum(Func selector) { if (_disposed) { return 0; } _lock.EnterReadLock(); try { return _items.Sum(selector); } finally { _lock.ExitReadLock(); } } /// /// Returns a number that represents how many elements in the specified sequence satisfy a condition. /// /// /// long? number of found elements public long? Sum(Func selector) { if (_disposed) { return 0; } _lock.EnterReadLock(); try { return _items.Sum(selector); } finally { _lock.ExitReadLock(); } } /// /// Returns a number that represents how many elements in the specified sequence satisfy a condition. /// /// /// number of found elements public double Sum(Func selector) { if (_disposed) { return 0; } _lock.EnterReadLock(); try { return _items.Sum(selector); } finally { _lock.ExitReadLock(); } } /// /// Returns a number that represents how many elements in the specified sequence satisfy a condition. /// /// /// double? number of found elements public double? Sum(Func selector) { if (_disposed) { return 0; } _lock.EnterReadLock(); try { return _items.Sum(selector); } finally { _lock.ExitReadLock(); } } /// /// Filters a sequence of values based on a predicate. /// /// /// /// /// public List Where(Func predicate) { if (_disposed) { return new List(); } _lock.EnterReadLock(); try { return _items.Where(predicate).ToList(); } finally { _lock.ExitReadLock(); } } protected virtual void Dispose(bool disposing) { if (!disposing) { return; } Clear(); _lock.Dispose(); } #endregion }