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