coding styles nullable
This commit is contained in:
@@ -3,50 +3,47 @@ using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Swan.Collections
|
||||
{
|
||||
namespace Swan.Collections {
|
||||
/// <summary>
|
||||
/// A thread-safe collection cache repository for types.
|
||||
/// </summary>
|
||||
/// <typeparam name="TValue">The type of member to cache.</typeparam>
|
||||
public class CollectionCacheRepository<TValue> {
|
||||
private readonly Lazy<ConcurrentDictionary<Type, IEnumerable<TValue>>> _data = new Lazy<ConcurrentDictionary<Type, IEnumerable<TValue>>>(() => new ConcurrentDictionary<Type, IEnumerable<TValue>>(), true);
|
||||
|
||||
/// <summary>
|
||||
/// A thread-safe collection cache repository for types.
|
||||
/// Determines whether the cache contains the specified key.
|
||||
/// </summary>
|
||||
/// <typeparam name="TValue">The type of member to cache.</typeparam>
|
||||
public class CollectionCacheRepository<TValue>
|
||||
{
|
||||
private readonly Lazy<ConcurrentDictionary<Type, IEnumerable<TValue>>> _data =
|
||||
new Lazy<ConcurrentDictionary<Type, IEnumerable<TValue>>>(() =>
|
||||
new ConcurrentDictionary<Type, IEnumerable<TValue>>(), true);
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the cache contains the specified key.
|
||||
/// </summary>
|
||||
/// <param name="key">The key.</param>
|
||||
/// <returns><c>true</c> if the cache contains the key, otherwise <c>false</c>.</returns>
|
||||
public bool ContainsKey(Type key) => _data.Value.ContainsKey(key);
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the properties stored for the specified type.
|
||||
/// If the properties are not available, it calls the factory method to retrieve them
|
||||
/// and returns them as an array of PropertyInfo.
|
||||
/// </summary>
|
||||
/// <param name="key">The key.</param>
|
||||
/// <param name="factory">The factory.</param>
|
||||
/// <returns>
|
||||
/// An array of the properties stored for the specified type.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// key
|
||||
/// or
|
||||
/// factory.
|
||||
/// </exception>
|
||||
/// <exception cref="System.ArgumentNullException">type.</exception>
|
||||
public IEnumerable<TValue> Retrieve(Type key, Func<Type, IEnumerable<TValue>> factory)
|
||||
{
|
||||
if (key == null)
|
||||
throw new ArgumentNullException(nameof(key));
|
||||
|
||||
if (factory == null)
|
||||
throw new ArgumentNullException(nameof(factory));
|
||||
|
||||
return _data.Value.GetOrAdd(key, k => factory.Invoke(k).Where(item => item != null));
|
||||
}
|
||||
}
|
||||
/// <param name="key">The key.</param>
|
||||
/// <returns><c>true</c> if the cache contains the key, otherwise <c>false</c>.</returns>
|
||||
public Boolean ContainsKey(Type key) => this._data.Value.ContainsKey(key);
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the properties stored for the specified type.
|
||||
/// If the properties are not available, it calls the factory method to retrieve them
|
||||
/// and returns them as an array of PropertyInfo.
|
||||
/// </summary>
|
||||
/// <param name="key">The key.</param>
|
||||
/// <param name="factory">The factory.</param>
|
||||
/// <returns>
|
||||
/// An array of the properties stored for the specified type.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// key
|
||||
/// or
|
||||
/// factory.
|
||||
/// </exception>
|
||||
/// <exception cref="System.ArgumentNullException">type.</exception>
|
||||
public IEnumerable<TValue> Retrieve(Type key, Func<Type, IEnumerable<TValue>> factory) {
|
||||
if(key == null) {
|
||||
throw new ArgumentNullException(nameof(key));
|
||||
}
|
||||
|
||||
if(factory == null) {
|
||||
throw new ArgumentNullException(nameof(factory));
|
||||
}
|
||||
|
||||
return this._data.Value.GetOrAdd(key, k => factory.Invoke(k).Where(item => item != null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,74 +3,75 @@ using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Swan.Configuration;
|
||||
|
||||
namespace Swan.Collections
|
||||
{
|
||||
namespace Swan.Collections {
|
||||
/// <summary>
|
||||
/// <para>Implements a collection of components.</para>
|
||||
/// <para>Each component in the collection may be given a unique name for later retrieval.</para>
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of components in the collection.</typeparam>
|
||||
/// <seealso cref="IComponentCollection{T}" />
|
||||
public class ComponentCollection<T> : ConfiguredObject, IComponentCollection<T> {
|
||||
private readonly List<T> _components = new List<T>();
|
||||
|
||||
private readonly List<(String, T)> _componentsWithSafeNames = new List<(String, T)>();
|
||||
|
||||
private readonly Dictionary<String, T> _namedComponents = new Dictionary<String, T>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public Int32 Count => this._components.Count;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IReadOnlyDictionary<String, T> Named => this._namedComponents;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IReadOnlyList<(String SafeName, T Component)> WithSafeNames => this._componentsWithSafeNames;
|
||||
|
||||
/// <inheritdoc />
|
||||
public T this[Int32 index] => this._components[index];
|
||||
|
||||
/// <inheritdoc />
|
||||
public T this[String key] => this._namedComponents[key];
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerator<T> GetEnumerator() => this._components.GetEnumerator();
|
||||
|
||||
/// <inheritdoc />
|
||||
IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)this._components).GetEnumerator();
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <exception cref="InvalidOperationException">The collection is locked.</exception>
|
||||
public void Add(String name, T component) {
|
||||
this.EnsureConfigurationNotLocked();
|
||||
|
||||
if(name != null) {
|
||||
if(name.Length == 0) {
|
||||
throw new ArgumentException("Component name is empty.", nameof(name));
|
||||
}
|
||||
|
||||
if(this._namedComponents.ContainsKey(name)) {
|
||||
throw new ArgumentException("Duplicate component name.", nameof(name));
|
||||
}
|
||||
}
|
||||
|
||||
if(component == null) {
|
||||
throw new ArgumentNullException(nameof(component));
|
||||
}
|
||||
|
||||
if(this._components.Contains(component)) {
|
||||
throw new ArgumentException("Component has already been added.", nameof(component));
|
||||
}
|
||||
|
||||
this._components.Add(component);
|
||||
this._componentsWithSafeNames.Add((name ?? $"<{component.GetType().Name}>", component));
|
||||
|
||||
if(name != null) {
|
||||
this._namedComponents.Add(name, component);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <para>Implements a collection of components.</para>
|
||||
/// <para>Each component in the collection may be given a unique name for later retrieval.</para>
|
||||
/// Locks the collection, preventing further additions.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of components in the collection.</typeparam>
|
||||
/// <seealso cref="IComponentCollection{T}" />
|
||||
public class ComponentCollection<T> : ConfiguredObject, IComponentCollection<T>
|
||||
{
|
||||
private readonly List<T> _components = new List<T>();
|
||||
|
||||
private readonly List<(string, T)> _componentsWithSafeNames = new List<(string, T)>();
|
||||
|
||||
private readonly Dictionary<string, T> _namedComponents = new Dictionary<string, T>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public int Count => _components.Count;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IReadOnlyDictionary<string, T> Named => _namedComponents;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IReadOnlyList<(string SafeName, T Component)> WithSafeNames => _componentsWithSafeNames;
|
||||
|
||||
/// <inheritdoc />
|
||||
public T this[int index] => _components[index];
|
||||
|
||||
/// <inheritdoc />
|
||||
public T this[string key] => _namedComponents[key];
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerator<T> GetEnumerator() => _components.GetEnumerator();
|
||||
|
||||
/// <inheritdoc />
|
||||
IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)_components).GetEnumerator();
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <exception cref="InvalidOperationException">The collection is locked.</exception>
|
||||
public void Add(string name, T component)
|
||||
{
|
||||
EnsureConfigurationNotLocked();
|
||||
|
||||
if (name != null)
|
||||
{
|
||||
if (name.Length == 0)
|
||||
throw new ArgumentException("Component name is empty.", nameof(name));
|
||||
|
||||
if (_namedComponents.ContainsKey(name))
|
||||
throw new ArgumentException("Duplicate component name.", nameof(name));
|
||||
}
|
||||
|
||||
if (component == null)
|
||||
throw new ArgumentNullException(nameof(component));
|
||||
|
||||
if (_components.Contains(component))
|
||||
throw new ArgumentException("Component has already been added.", nameof(component));
|
||||
|
||||
_components.Add(component);
|
||||
_componentsWithSafeNames.Add((name ?? $"<{component.GetType().Name}>", component));
|
||||
|
||||
if (name != null)
|
||||
_namedComponents.Add(name, component);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Locks the collection, preventing further additions.
|
||||
/// </summary>
|
||||
public void Lock() => LockConfiguration();
|
||||
}
|
||||
public void Lock() => this.LockConfiguration();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,301 +4,266 @@ using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Swan.Collections
|
||||
{
|
||||
namespace Swan.Collections {
|
||||
/// <summary>
|
||||
/// Represents a thread-safe collection of key/value pairs that does not store null values
|
||||
/// and can be accessed by multiple threads concurrently.
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey">The type of keys in the dictionary. This must be a reference type.</typeparam>
|
||||
/// <typeparam name="TValue">The type of values in the dictionary. This must be a reference type.</typeparam>
|
||||
/// <seealso cref="IDataDictionary{TKey,TValue}"/>
|
||||
public sealed class ConcurrentDataDictionary<TKey, TValue> : IDataDictionary<TKey, TValue> where TKey : class where TValue : class {
|
||||
#region Private data
|
||||
|
||||
private readonly ConcurrentDictionary<TKey, TValue> _dictionary;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Instance management
|
||||
|
||||
/// <summary>
|
||||
/// Represents a thread-safe collection of key/value pairs that does not store null values
|
||||
/// and can be accessed by multiple threads concurrently.
|
||||
/// Initializes a new instance of the <see cref="ConcurrentDataDictionary{TKey,TValue}"/> class
|
||||
/// that is empty, has the default concurrency level, has the default initial capacity,
|
||||
/// and uses the default comparer for <typeparamref name="TKey"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey">The type of keys in the dictionary. This must be a reference type.</typeparam>
|
||||
/// <typeparam name="TValue">The type of values in the dictionary. This must be a reference type.</typeparam>
|
||||
/// <seealso cref="IDataDictionary{TKey,TValue}"/>
|
||||
public sealed class ConcurrentDataDictionary<TKey, TValue> : IDataDictionary<TKey, TValue>
|
||||
where TKey : class
|
||||
where TValue : class
|
||||
{
|
||||
#region Private data
|
||||
|
||||
private readonly ConcurrentDictionary<TKey, TValue> _dictionary;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Instance management
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ConcurrentDataDictionary{TKey,TValue}"/> class
|
||||
/// that is empty, has the default concurrency level, has the default initial capacity,
|
||||
/// and uses the default comparer for <typeparamref name="TKey"/>.
|
||||
/// </summary>
|
||||
/// <see cref="ConcurrentDictionary{TKey,TValue}()"/>
|
||||
public ConcurrentDataDictionary()
|
||||
{
|
||||
_dictionary = new ConcurrentDictionary<TKey, TValue>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ConcurrentDataDictionary{TKey,TValue}"/> class
|
||||
/// that contains elements copied from the specified <see cref="IEnumerable{T}"/>, has the default concurrency level,
|
||||
/// has the default initial capacity, and uses the default comparer for <typeparamref name="TKey"/>.
|
||||
/// </summary>
|
||||
/// <param name="collection">The <see cref="IEnumerable{T}"/> whose elements are copied
|
||||
/// to the new <see cref="ConcurrentDataDictionary{TKey,TValue}"/>.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="collection"/> is <see langword="null"/>.</exception>
|
||||
/// <remarks>
|
||||
/// <para>Since <see cref="ConcurrentDataDictionary{TKey,TValue}"/> does not store null values,
|
||||
/// key/value pairs whose value is <see langword="null"/> will not be copied from <paramref name="collection"/>.</para>
|
||||
/// </remarks>
|
||||
/// <see cref="ConcurrentDictionary{TKey,TValue}(IEnumerable{KeyValuePair{TKey,TValue}})"/>
|
||||
public ConcurrentDataDictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection)
|
||||
{
|
||||
if (collection == null)
|
||||
throw new ArgumentNullException(nameof(collection));
|
||||
|
||||
_dictionary = new ConcurrentDictionary<TKey, TValue>(collection.Where(pair => pair.Value != null));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ConcurrentDataDictionary{TKey,TValue}"/> class
|
||||
/// that is empty, has the default concurrency level and capacity, and uses the specified <see cref="IEqualityComparer{T}"/>.
|
||||
/// </summary>
|
||||
/// <param name="comparer">The equality comparison implementation to use when comparing keys.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="comparer"/> is <see langword="null"/>.</exception>
|
||||
/// <see cref="ConcurrentDictionary{TKey,TValue}(IEqualityComparer{TKey})"/>
|
||||
public ConcurrentDataDictionary(IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
_dictionary = new ConcurrentDictionary<TKey, TValue>(comparer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ConcurrentDataDictionary{TKey, TValue}"/> class
|
||||
/// that contains elements copied from the specified <see cref="IEnumerable{T}"/>, has the default concurrency level,
|
||||
/// has the default initial capacity, and uses the specified <see cref="IEqualityComparer{T}"/>.
|
||||
/// </summary>
|
||||
/// <param name="collection">The <see cref="IEnumerable{T}"/> whose elements are copied
|
||||
/// to the new <see cref="ConcurrentDataDictionary{TKey,TValue}"/>.</param>
|
||||
/// <param name="comparer">The equality comparison implementation to use when comparing keys.</param>
|
||||
/// <remarks>
|
||||
/// <para>Since <see cref="ConcurrentDataDictionary{TKey,TValue}"/> does not store null values,
|
||||
/// key/value pairs whose value is <see langword="null"/> will not be copied from <paramref name="collection"/>.</para>
|
||||
/// </remarks>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <para><paramref name="collection"/> is <see langword="null"/>.</para>
|
||||
/// <para>- or -.</para>
|
||||
/// <para><paramref name="comparer"/> is <see langword="null"/>.</para>
|
||||
/// </exception>
|
||||
/// <see cref="ConcurrentDictionary{TKey,TValue}(IEnumerable{KeyValuePair{TKey,TValue}},IEqualityComparer{TKey})"/>
|
||||
public ConcurrentDataDictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
if (collection == null)
|
||||
throw new ArgumentNullException(nameof(collection));
|
||||
|
||||
_dictionary = new ConcurrentDictionary<TKey, TValue>(collection.Where(pair => pair.Value != null), comparer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ConcurrentDataDictionary{TKey, TValue}"/> class
|
||||
/// that is empty, has the specified concurrency level and capacity, and uses the default comparer for the key type.
|
||||
/// </summary>
|
||||
/// <param name="concurrencyLevel">The estimated number of threads that will update
|
||||
/// the <see cref="ConcurrentDataDictionary{TKey, TValue}"/> concurrently.</param>
|
||||
/// <param name="capacity">The initial number of elements that the <see cref="ConcurrentDataDictionary{TKey, TValue}"/> can contain.</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// <para><paramref name="concurrencyLevel"/> is less than 1.</para>
|
||||
/// <para>- or -.</para>
|
||||
/// <para><paramref name="capacity"/> is less than 0.</para>
|
||||
/// </exception>
|
||||
/// <see cref="ConcurrentDictionary{TKey,TValue}(int,int)"/>
|
||||
public ConcurrentDataDictionary(int concurrencyLevel, int capacity)
|
||||
{
|
||||
_dictionary = new ConcurrentDictionary<TKey, TValue>(concurrencyLevel, capacity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ConcurrentDataDictionary{TKey, TValue}"/> class
|
||||
/// that contains elements copied from the specified <see cref="IEnumerable{T}"/>, has the specified concurrency level,
|
||||
/// has the default initial capacity, and uses the specified <see cref="IEqualityComparer{T}"/>.
|
||||
/// </summary>
|
||||
/// <param name="concurrencyLevel">The estimated number of threads that will update
|
||||
/// the <see cref="ConcurrentDataDictionary{TKey, TValue}"/> concurrently.</param>
|
||||
/// <param name="collection">The <see cref="IEnumerable{T}"/> whose elements are copied
|
||||
/// to the new <see cref="ConcurrentDataDictionary{TKey,TValue}"/>.</param>
|
||||
/// <param name="comparer">The equality comparison implementation to use when comparing keys.</param>
|
||||
/// <remarks>
|
||||
/// <para>Since <see cref="ConcurrentDataDictionary{TKey,TValue}"/> does not store null values,
|
||||
/// key/value pairs whose value is <see langword="null"/> will not be copied from <paramref name="collection"/>.</para>
|
||||
/// </remarks>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <para><paramref name="collection"/> is <see langword="null"/>.</para>
|
||||
/// <para>- or -.</para>
|
||||
/// <para><paramref name="comparer"/> is <see langword="null"/>.</para>
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException"><paramref name="concurrencyLevel"/> is less than 1.</exception>
|
||||
/// <see cref="ConcurrentDictionary{TKey,TValue}(int,IEnumerable{KeyValuePair{TKey,TValue}},IEqualityComparer{TKey})"/>
|
||||
public ConcurrentDataDictionary(int concurrencyLevel, IEnumerable<KeyValuePair<TKey, TValue>> collection, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
if (collection == null)
|
||||
throw new ArgumentNullException(nameof(collection));
|
||||
|
||||
_dictionary = new ConcurrentDictionary<TKey, TValue>(
|
||||
concurrencyLevel,
|
||||
collection.Where(pair => pair.Value != null),
|
||||
comparer);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public APIs
|
||||
|
||||
/// <inheritdoc cref="IDataDictionary{TKey,TValue}.Count"/>
|
||||
public int Count => _dictionary.Count;
|
||||
|
||||
/// <inheritdoc cref="IDataDictionary{TKey,TValue}.IsEmpty"/>
|
||||
public bool IsEmpty => _dictionary.IsEmpty;
|
||||
|
||||
/// <inheritdoc cref="IDictionary{TKey,TValue}.Keys"/>
|
||||
public ICollection<TKey> Keys => _dictionary.Keys;
|
||||
|
||||
/// <inheritdoc cref="IDictionary{TKey,TValue}.Values"/>
|
||||
public ICollection<TValue> Values => _dictionary.Values;
|
||||
|
||||
/// <inheritdoc cref="IDataDictionary{TKey,TValue}.this"/>
|
||||
public TValue? this[TKey key]
|
||||
{
|
||||
get => _dictionary.TryGetValue(key ?? throw new ArgumentNullException(nameof(key)), out var value) ? value : null;
|
||||
set
|
||||
{
|
||||
if (value != null)
|
||||
{
|
||||
_dictionary[key] = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
_dictionary.TryRemove(key, out _);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IDataDictionary{TKey,TValue}.Clear"/>
|
||||
public void Clear() => _dictionary.Clear();
|
||||
|
||||
/// <inheritdoc cref="IDataDictionary{TKey,TValue}.ContainsKey"/>
|
||||
public bool ContainsKey(TKey key) => _dictionary.ContainsKey(key);
|
||||
|
||||
/// <inheritdoc cref="ConcurrentDictionary{TKey,TValue}.GetOrAdd(TKey,TValue)"/>
|
||||
public TValue? GetOrAdd(TKey key, TValue value)
|
||||
{
|
||||
if (key == null)
|
||||
throw new ArgumentNullException(nameof(key));
|
||||
|
||||
if (value != null)
|
||||
return _dictionary.GetOrAdd(key, value);
|
||||
|
||||
return _dictionary.TryGetValue(key, out var retrievedValue) ? retrievedValue : null;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IDictionary{TKey,TValue}.Remove(TKey)"/>
|
||||
public bool Remove(TKey key) => _dictionary.TryRemove(key, out _);
|
||||
|
||||
/// <inheritdoc cref="ConcurrentDictionary{TKey,TValue}.TryAdd"/>
|
||||
public bool TryAdd(TKey key, TValue value)
|
||||
{
|
||||
if (key == null)
|
||||
throw new ArgumentNullException(nameof(key));
|
||||
|
||||
return value == null || _dictionary.TryAdd(key, value);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IDataDictionary{TKey,TValue}.TryGetValue"/>
|
||||
public bool TryGetValue(TKey key, out TValue value) => _dictionary.TryGetValue(key, out value);
|
||||
|
||||
/// <inheritdoc cref="IDataDictionary{TKey,TValue}.TryRemove"/>
|
||||
public bool TryRemove(TKey key, out TValue value) => _dictionary.TryRemove(key, out value);
|
||||
|
||||
/// <inheritdoc cref="ConcurrentDictionary{TKey,TValue}.TryUpdate"/>
|
||||
public bool TryUpdate(TKey key, TValue newValue, TValue comparisonValue)
|
||||
{
|
||||
if (key == null)
|
||||
throw new ArgumentNullException(nameof(key));
|
||||
|
||||
return newValue != null && comparisonValue != null && _dictionary.TryUpdate(key, newValue, comparisonValue);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Implementation of IDictionary<TKey, TValue>
|
||||
|
||||
/// <inheritdoc cref="IDictionary{TKey,TValue}.Add(TKey,TValue)"/>
|
||||
void IDictionary<TKey, TValue>.Add(TKey key, TValue value)
|
||||
{
|
||||
if (value != null)
|
||||
{
|
||||
((IDictionary<TKey, TValue>)_dictionary).Add(key, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
_dictionary.TryRemove(key, out _);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Implementation of IReadOnlyDictionary<TKey, TValue>
|
||||
|
||||
/// <inheritdoc cref="IReadOnlyDictionary{TKey,TValue}.Keys"/>
|
||||
IEnumerable<TKey> IReadOnlyDictionary<TKey, TValue>.Keys => _dictionary.Keys;
|
||||
|
||||
/// <inheritdoc cref="IReadOnlyDictionary{TKey,TValue}.Values"/>
|
||||
IEnumerable<TValue> IReadOnlyDictionary<TKey, TValue>.Values => _dictionary.Values;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Implementation of ICollection<KeyValuePair<TKey, TValue>>
|
||||
|
||||
/// <inheritdoc cref="ICollection{T}.IsReadOnly"/>
|
||||
/// <remarks>
|
||||
/// <para>This property is always <see langword="false"/> for a <see cref="ConcurrentDataDictionary{TKey,TValue}"/>.</para>
|
||||
/// </remarks>
|
||||
bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly => false;
|
||||
|
||||
/// <inheritdoc cref="ICollection{T}.Add"/>
|
||||
void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)
|
||||
{
|
||||
if (item.Value != null)
|
||||
{
|
||||
((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).Add(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
_dictionary.TryRemove(item.Key, out _);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="ICollection{T}.Contains"/>
|
||||
bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)
|
||||
=> ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).Contains(item);
|
||||
|
||||
/// <inheritdoc cref="ICollection{T}.CopyTo"/>
|
||||
void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
|
||||
=> ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).CopyTo(array, arrayIndex);
|
||||
|
||||
/// <inheritdoc cref="ICollection{T}.Remove"/>
|
||||
bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
|
||||
=> ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).Remove(item);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Implementation of IEnumerable<KeyValuePair<TKey, TValue>>
|
||||
|
||||
/// <inheritdoc cref="IEnumerable{T}.GetEnumerator"/>
|
||||
IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator() => _dictionary.GetEnumerator();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Implementation of IEnumerable
|
||||
|
||||
/// <inheritdoc cref="IEnumerable.GetEnumerator"/>
|
||||
IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)_dictionary).GetEnumerator();
|
||||
|
||||
#endregion
|
||||
}
|
||||
/// <see cref="ConcurrentDictionary{TKey,TValue}()"/>
|
||||
public ConcurrentDataDictionary() => this._dictionary = new ConcurrentDictionary<TKey, TValue>();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ConcurrentDataDictionary{TKey,TValue}"/> class
|
||||
/// that contains elements copied from the specified <see cref="IEnumerable{T}"/>, has the default concurrency level,
|
||||
/// has the default initial capacity, and uses the default comparer for <typeparamref name="TKey"/>.
|
||||
/// </summary>
|
||||
/// <param name="collection">The <see cref="IEnumerable{T}"/> whose elements are copied
|
||||
/// to the new <see cref="ConcurrentDataDictionary{TKey,TValue}"/>.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="collection"/> is <see langword="null"/>.</exception>
|
||||
/// <remarks>
|
||||
/// <para>Since <see cref="ConcurrentDataDictionary{TKey,TValue}"/> does not store null values,
|
||||
/// key/value pairs whose value is <see langword="null"/> will not be copied from <paramref name="collection"/>.</para>
|
||||
/// </remarks>
|
||||
/// <see cref="ConcurrentDictionary{TKey,TValue}(IEnumerable{KeyValuePair{TKey,TValue}})"/>
|
||||
public ConcurrentDataDictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection) {
|
||||
if(collection == null) {
|
||||
throw new ArgumentNullException(nameof(collection));
|
||||
}
|
||||
|
||||
this._dictionary = new ConcurrentDictionary<TKey, TValue>(collection.Where(pair => pair.Value != null));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ConcurrentDataDictionary{TKey,TValue}"/> class
|
||||
/// that is empty, has the default concurrency level and capacity, and uses the specified <see cref="IEqualityComparer{T}"/>.
|
||||
/// </summary>
|
||||
/// <param name="comparer">The equality comparison implementation to use when comparing keys.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="comparer"/> is <see langword="null"/>.</exception>
|
||||
/// <see cref="ConcurrentDictionary{TKey,TValue}(IEqualityComparer{TKey})"/>
|
||||
public ConcurrentDataDictionary(IEqualityComparer<TKey> comparer) => this._dictionary = new ConcurrentDictionary<TKey, TValue>(comparer);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ConcurrentDataDictionary{TKey, TValue}"/> class
|
||||
/// that contains elements copied from the specified <see cref="IEnumerable{T}"/>, has the default concurrency level,
|
||||
/// has the default initial capacity, and uses the specified <see cref="IEqualityComparer{T}"/>.
|
||||
/// </summary>
|
||||
/// <param name="collection">The <see cref="IEnumerable{T}"/> whose elements are copied
|
||||
/// to the new <see cref="ConcurrentDataDictionary{TKey,TValue}"/>.</param>
|
||||
/// <param name="comparer">The equality comparison implementation to use when comparing keys.</param>
|
||||
/// <remarks>
|
||||
/// <para>Since <see cref="ConcurrentDataDictionary{TKey,TValue}"/> does not store null values,
|
||||
/// key/value pairs whose value is <see langword="null"/> will not be copied from <paramref name="collection"/>.</para>
|
||||
/// </remarks>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <para><paramref name="collection"/> is <see langword="null"/>.</para>
|
||||
/// <para>- or -.</para>
|
||||
/// <para><paramref name="comparer"/> is <see langword="null"/>.</para>
|
||||
/// </exception>
|
||||
/// <see cref="ConcurrentDictionary{TKey,TValue}(IEnumerable{KeyValuePair{TKey,TValue}},IEqualityComparer{TKey})"/>
|
||||
public ConcurrentDataDictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection, IEqualityComparer<TKey> comparer) {
|
||||
if(collection == null) {
|
||||
throw new ArgumentNullException(nameof(collection));
|
||||
}
|
||||
|
||||
this._dictionary = new ConcurrentDictionary<TKey, TValue>(collection.Where(pair => pair.Value != null), comparer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ConcurrentDataDictionary{TKey, TValue}"/> class
|
||||
/// that is empty, has the specified concurrency level and capacity, and uses the default comparer for the key type.
|
||||
/// </summary>
|
||||
/// <param name="concurrencyLevel">The estimated number of threads that will update
|
||||
/// the <see cref="ConcurrentDataDictionary{TKey, TValue}"/> concurrently.</param>
|
||||
/// <param name="capacity">The initial number of elements that the <see cref="ConcurrentDataDictionary{TKey, TValue}"/> can contain.</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// <para><paramref name="concurrencyLevel"/> is less than 1.</para>
|
||||
/// <para>- or -.</para>
|
||||
/// <para><paramref name="capacity"/> is less than 0.</para>
|
||||
/// </exception>
|
||||
/// <see cref="ConcurrentDictionary{TKey,TValue}(Int32,Int32)"/>
|
||||
public ConcurrentDataDictionary(Int32 concurrencyLevel, Int32 capacity) => this._dictionary = new ConcurrentDictionary<TKey, TValue>(concurrencyLevel, capacity);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ConcurrentDataDictionary{TKey, TValue}"/> class
|
||||
/// that contains elements copied from the specified <see cref="IEnumerable{T}"/>, has the specified concurrency level,
|
||||
/// has the default initial capacity, and uses the specified <see cref="IEqualityComparer{T}"/>.
|
||||
/// </summary>
|
||||
/// <param name="concurrencyLevel">The estimated number of threads that will update
|
||||
/// the <see cref="ConcurrentDataDictionary{TKey, TValue}"/> concurrently.</param>
|
||||
/// <param name="collection">The <see cref="IEnumerable{T}"/> whose elements are copied
|
||||
/// to the new <see cref="ConcurrentDataDictionary{TKey,TValue}"/>.</param>
|
||||
/// <param name="comparer">The equality comparison implementation to use when comparing keys.</param>
|
||||
/// <remarks>
|
||||
/// <para>Since <see cref="ConcurrentDataDictionary{TKey,TValue}"/> does not store null values,
|
||||
/// key/value pairs whose value is <see langword="null"/> will not be copied from <paramref name="collection"/>.</para>
|
||||
/// </remarks>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <para><paramref name="collection"/> is <see langword="null"/>.</para>
|
||||
/// <para>- or -.</para>
|
||||
/// <para><paramref name="comparer"/> is <see langword="null"/>.</para>
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException"><paramref name="concurrencyLevel"/> is less than 1.</exception>
|
||||
/// <see cref="ConcurrentDictionary{TKey,TValue}(Int32,IEnumerable{KeyValuePair{TKey,TValue}},IEqualityComparer{TKey})"/>
|
||||
public ConcurrentDataDictionary(Int32 concurrencyLevel, IEnumerable<KeyValuePair<TKey, TValue>> collection, IEqualityComparer<TKey> comparer) {
|
||||
if(collection == null) {
|
||||
throw new ArgumentNullException(nameof(collection));
|
||||
}
|
||||
|
||||
this._dictionary = new ConcurrentDictionary<TKey, TValue>(concurrencyLevel, collection.Where(pair => pair.Value != null), comparer);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public APIs
|
||||
|
||||
/// <inheritdoc cref="IDataDictionary{TKey,TValue}.Count"/>
|
||||
public Int32 Count => this._dictionary.Count;
|
||||
|
||||
/// <inheritdoc cref="IDataDictionary{TKey,TValue}.IsEmpty"/>
|
||||
public Boolean IsEmpty => this._dictionary.IsEmpty;
|
||||
|
||||
/// <inheritdoc cref="IDictionary{TKey,TValue}.Keys"/>
|
||||
public ICollection<TKey> Keys => this._dictionary.Keys;
|
||||
|
||||
/// <inheritdoc cref="IDictionary{TKey,TValue}.Values"/>
|
||||
public ICollection<TValue> Values => this._dictionary.Values;
|
||||
|
||||
/// <inheritdoc cref="IDataDictionary{TKey,TValue}.this"/>
|
||||
public TValue this[TKey key] {
|
||||
get => this._dictionary.TryGetValue(key ?? throw new ArgumentNullException(nameof(key)), out TValue value) ? value : null;
|
||||
set {
|
||||
if(value != null) {
|
||||
this._dictionary[key] = value;
|
||||
} else {
|
||||
_ = this._dictionary.TryRemove(key, out _);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IDataDictionary{TKey,TValue}.Clear"/>
|
||||
public void Clear() => this._dictionary.Clear();
|
||||
|
||||
/// <inheritdoc cref="IDataDictionary{TKey,TValue}.ContainsKey"/>
|
||||
public Boolean ContainsKey(TKey key) => this._dictionary.ContainsKey(key);
|
||||
|
||||
/// <inheritdoc cref="ConcurrentDictionary{TKey,TValue}.GetOrAdd(TKey,TValue)"/>
|
||||
public TValue GetOrAdd(TKey key, TValue value) {
|
||||
if(key == null) {
|
||||
throw new ArgumentNullException(nameof(key));
|
||||
}
|
||||
|
||||
return value != null ? this._dictionary.GetOrAdd(key, value) : this._dictionary.TryGetValue(key, out TValue retrievedValue) ? retrievedValue : null;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IDictionary{TKey,TValue}.Remove(TKey)"/>
|
||||
public Boolean Remove(TKey key) => this._dictionary.TryRemove(key, out _);
|
||||
|
||||
/// <inheritdoc cref="ConcurrentDictionary{TKey,TValue}.TryAdd"/>
|
||||
public Boolean TryAdd(TKey key, TValue value) {
|
||||
if(key == null) {
|
||||
throw new ArgumentNullException(nameof(key));
|
||||
}
|
||||
|
||||
return value == null || this._dictionary.TryAdd(key, value);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IDataDictionary{TKey,TValue}.TryGetValue"/>
|
||||
public Boolean TryGetValue(TKey key, out TValue value) => this._dictionary.TryGetValue(key, out value);
|
||||
|
||||
/// <inheritdoc cref="IDataDictionary{TKey,TValue}.TryRemove"/>
|
||||
public Boolean TryRemove(TKey key, out TValue value) => this._dictionary.TryRemove(key, out value);
|
||||
|
||||
/// <inheritdoc cref="ConcurrentDictionary{TKey,TValue}.TryUpdate"/>
|
||||
public Boolean TryUpdate(TKey key, TValue newValue, TValue comparisonValue) {
|
||||
if(key == null) {
|
||||
throw new ArgumentNullException(nameof(key));
|
||||
}
|
||||
|
||||
return newValue != null && comparisonValue != null && this._dictionary.TryUpdate(key, newValue, comparisonValue);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Implementation of IDictionary<TKey, TValue>
|
||||
|
||||
/// <inheritdoc cref="IDictionary{TKey,TValue}.Add(TKey,TValue)"/>
|
||||
void IDictionary<TKey, TValue>.Add(TKey key, TValue value) {
|
||||
if(value != null) {
|
||||
((IDictionary<TKey, TValue>)this._dictionary).Add(key, value);
|
||||
} else {
|
||||
_ = this._dictionary.TryRemove(key, out _);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Implementation of IReadOnlyDictionary<TKey, TValue>
|
||||
|
||||
/// <inheritdoc cref="IReadOnlyDictionary{TKey,TValue}.Keys"/>
|
||||
IEnumerable<TKey> IReadOnlyDictionary<TKey, TValue>.Keys => this._dictionary.Keys;
|
||||
|
||||
/// <inheritdoc cref="IReadOnlyDictionary{TKey,TValue}.Values"/>
|
||||
IEnumerable<TValue> IReadOnlyDictionary<TKey, TValue>.Values => this._dictionary.Values;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Implementation of ICollection<KeyValuePair<TKey, TValue>>
|
||||
|
||||
/// <inheritdoc cref="ICollection{T}.IsReadOnly"/>
|
||||
/// <remarks>
|
||||
/// <para>This property is always <see langword="false"/> for a <see cref="ConcurrentDataDictionary{TKey,TValue}"/>.</para>
|
||||
/// </remarks>
|
||||
Boolean ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly => false;
|
||||
|
||||
/// <inheritdoc cref="ICollection{T}.Add"/>
|
||||
void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item) {
|
||||
if(item.Value != null) {
|
||||
((ICollection<KeyValuePair<TKey, TValue>>)this._dictionary).Add(item);
|
||||
} else {
|
||||
_ = this._dictionary.TryRemove(item.Key, out _);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="ICollection{T}.Contains"/>
|
||||
Boolean ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item) => ((ICollection<KeyValuePair<TKey, TValue>>)this._dictionary).Contains(item);
|
||||
|
||||
/// <inheritdoc cref="ICollection{T}.CopyTo"/>
|
||||
void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, Int32 arrayIndex) => ((ICollection<KeyValuePair<TKey, TValue>>)this._dictionary).CopyTo(array, arrayIndex);
|
||||
|
||||
/// <inheritdoc cref="ICollection{T}.Remove"/>
|
||||
Boolean ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item) => ((ICollection<KeyValuePair<TKey, TValue>>)this._dictionary).Remove(item);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Implementation of IEnumerable<KeyValuePair<TKey, TValue>>
|
||||
|
||||
/// <inheritdoc cref="IEnumerable{T}.GetEnumerator"/>
|
||||
IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator() => this._dictionary.GetEnumerator();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Implementation of IEnumerable
|
||||
|
||||
/// <inheritdoc cref="IEnumerable.GetEnumerator"/>
|
||||
IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)this._dictionary).GetEnumerator();
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,341 +1,312 @@
|
||||
using System;
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Swan.Collections
|
||||
{
|
||||
namespace Swan.Collections {
|
||||
/// <summary>
|
||||
/// Represents a non-thread-safe collection of key/value pairs that does not store null values.
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey">The type of keys in the dictionary. This must be a reference type.</typeparam>
|
||||
/// <typeparam name="TValue">The type of values in the dictionary. This must be a reference type.</typeparam>
|
||||
/// <seealso cref="IDataDictionary{TKey,TValue}"/>
|
||||
public sealed class DataDictionary<TKey, TValue> : IDataDictionary<TKey, TValue>
|
||||
where TKey : class
|
||||
where TValue : class {
|
||||
#region Private data
|
||||
|
||||
private readonly Dictionary<TKey, TValue> _dictionary;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Instance management
|
||||
|
||||
/// <summary>
|
||||
/// Represents a non-thread-safe collection of key/value pairs that does not store null values.
|
||||
/// Initializes a new instance of the <see cref="DataDictionary{TKey,TValue}"/> class
|
||||
/// that is empty, has the default initial capacity,
|
||||
/// and uses the default comparer for <typeparamref name="TKey"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey">The type of keys in the dictionary. This must be a reference type.</typeparam>
|
||||
/// <typeparam name="TValue">The type of values in the dictionary. This must be a reference type.</typeparam>
|
||||
/// <seealso cref="IDataDictionary{TKey,TValue}"/>
|
||||
public sealed class DataDictionary<TKey, TValue> : IDataDictionary<TKey, TValue>
|
||||
where TKey : class
|
||||
where TValue : class
|
||||
{
|
||||
#region Private data
|
||||
|
||||
private readonly Dictionary<TKey, TValue> _dictionary;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Instance management
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DataDictionary{TKey,TValue}"/> class
|
||||
/// that is empty, has the default initial capacity,
|
||||
/// and uses the default comparer for <typeparamref name="TKey"/>.
|
||||
/// </summary>
|
||||
/// <see cref="Dictionary{TKey,TValue}()"/>
|
||||
public DataDictionary()
|
||||
{
|
||||
_dictionary = new Dictionary<TKey, TValue>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DataDictionary{TKey,TValue}"/> class
|
||||
/// that contains elements copied from the specified <see cref="IEnumerable{T}"/>,
|
||||
/// has the default initial capacity, and uses the default comparer for <typeparamref name="TKey"/>.
|
||||
/// </summary>
|
||||
/// <param name="collection">The <see cref="IEnumerable{T}"/> whose elements are copied
|
||||
/// to the new <see cref="DataDictionary{TKey,TValue}"/>.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="collection"/> is <see langword="null"/>.</exception>
|
||||
/// <remarks>
|
||||
/// <para>Since <see cref="DataDictionary{TKey,TValue}"/> does not store null values,
|
||||
/// key/value pairs whose value is <see langword="null"/> will not be copied from <paramref name="collection"/>.</para>
|
||||
/// </remarks>
|
||||
/// <see cref="Dictionary{TKey,TValue}()"/>
|
||||
public DataDictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection)
|
||||
{
|
||||
if (collection == null)
|
||||
throw new ArgumentNullException(nameof(collection));
|
||||
|
||||
_dictionary = new Dictionary<TKey, TValue>();
|
||||
foreach (var pair in collection.Where(pair => pair.Value != null))
|
||||
{
|
||||
_dictionary.Add(pair.Key, pair.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DataDictionary{TKey,TValue}"/> class
|
||||
/// that is empty, has the default capacity, and uses the specified <see cref="IEqualityComparer{T}"/>.
|
||||
/// </summary>
|
||||
/// <param name="comparer">The equality comparison implementation to use when comparing keys.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="comparer"/> is <see langword="null"/>.</exception>
|
||||
/// <see cref="Dictionary{TKey,TValue}(IEqualityComparer{TKey})"/>
|
||||
public DataDictionary(IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
_dictionary = new Dictionary<TKey, TValue>(comparer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DataDictionary{TKey, TValue}"/> class
|
||||
/// that contains elements copied from the specified <see cref="IEnumerable{T}"/>,
|
||||
/// has the default initial capacity, and uses the specified <see cref="IEqualityComparer{T}"/>.
|
||||
/// </summary>
|
||||
/// <param name="collection">The <see cref="IEnumerable{T}"/> whose elements are copied
|
||||
/// to the new <see cref="DataDictionary{TKey,TValue}"/>.</param>
|
||||
/// <param name="comparer">The equality comparison implementation to use when comparing keys.</param>
|
||||
/// <remarks>
|
||||
/// <para>Since <see cref="DataDictionary{TKey,TValue}"/> does not store null values,
|
||||
/// key/value pairs whose value is <see langword="null"/> will not be copied from <paramref name="collection"/>.</para>
|
||||
/// </remarks>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <para><paramref name="collection"/> is <see langword="null"/>.</para>
|
||||
/// <para>- or -.</para>
|
||||
/// <para><paramref name="comparer"/> is <see langword="null"/>.</para>
|
||||
/// </exception>
|
||||
/// <see cref="Dictionary{TKey,TValue}(IEqualityComparer{TKey})"/>
|
||||
public DataDictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
if (collection == null)
|
||||
throw new ArgumentNullException(nameof(collection));
|
||||
|
||||
_dictionary = new Dictionary<TKey, TValue>(comparer);
|
||||
foreach (var pair in collection.Where(pair => pair.Value != null))
|
||||
{
|
||||
_dictionary.Add(pair.Key, pair.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DataDictionary{TKey, TValue}"/> class
|
||||
/// that is empty, has the specified capacity, and uses the default comparer for the key type.
|
||||
/// </summary>
|
||||
/// <param name="capacity">The initial number of elements that the <see cref="DataDictionary{TKey, TValue}"/> can contain.</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException"><paramref name="capacity"/> is less than 0.</exception>
|
||||
/// <see cref="Dictionary{TKey,TValue}(int)"/>
|
||||
public DataDictionary(int capacity)
|
||||
{
|
||||
_dictionary = new Dictionary<TKey, TValue>(capacity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DataDictionary{TKey, TValue}"/> class
|
||||
/// that contains elements copied from the specified <see cref="IEnumerable{T}"/>,
|
||||
/// has the specified capacity, and uses the specified <see cref="IEqualityComparer{T}"/>.
|
||||
/// </summary>
|
||||
/// <param name="capacity">The initial number of elements that the <see cref="DataDictionary{TKey, TValue}"/> can contain.</param>
|
||||
/// <param name="collection">The <see cref="IEnumerable{T}"/> whose elements are copied
|
||||
/// to the new <see cref="ConcurrentDataDictionary{TKey,TValue}"/>.</param>
|
||||
/// <param name="comparer">The equality comparison implementation to use when comparing keys.</param>
|
||||
/// <remarks>
|
||||
/// <para>Since <see cref="ConcurrentDataDictionary{TKey,TValue}"/> does not store null values,
|
||||
/// key/value pairs whose value is <see langword="null"/> will not be copied from <paramref name="collection"/>.</para>
|
||||
/// </remarks>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <para><paramref name="collection"/> is <see langword="null"/>.</para>
|
||||
/// <para>- or -.</para>
|
||||
/// <para><paramref name="comparer"/> is <see langword="null"/>.</para>
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException"><paramref name="capacity"/> is less than 0.</exception>
|
||||
/// <see cref="Dictionary{TKey,TValue}(int,IEqualityComparer{TKey})"/>
|
||||
public DataDictionary(int capacity, IEnumerable<KeyValuePair<TKey, TValue>> collection, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
if (collection == null)
|
||||
throw new ArgumentNullException(nameof(collection));
|
||||
|
||||
_dictionary = new Dictionary<TKey, TValue>(capacity, comparer);
|
||||
foreach (var pair in collection.Where(pair => pair.Value != null))
|
||||
{
|
||||
_dictionary.Add(pair.Key, pair.Value);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public APIs
|
||||
|
||||
/// <inheritdoc cref="IDataDictionary{TKey,TValue}.Count"/>
|
||||
public int Count => _dictionary.Count;
|
||||
|
||||
/// <inheritdoc cref="IDataDictionary{TKey,TValue}.IsEmpty"/>
|
||||
public bool IsEmpty => _dictionary.Count == 0;
|
||||
|
||||
/// <inheritdoc cref="IDictionary{TKey,TValue}.Keys"/>
|
||||
public ICollection<TKey> Keys => _dictionary.Keys;
|
||||
|
||||
/// <inheritdoc cref="IDictionary{TKey,TValue}.Values"/>
|
||||
public ICollection<TValue> Values => _dictionary.Values;
|
||||
|
||||
/// <inheritdoc cref="IDataDictionary{TKey,TValue}.this"/>
|
||||
public TValue? this[TKey key]
|
||||
{
|
||||
get => _dictionary.TryGetValue(key ?? throw new ArgumentNullException(nameof(key)), out var value) ? value : null;
|
||||
set
|
||||
{
|
||||
if (value != null)
|
||||
{
|
||||
_dictionary[key] = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
_dictionary.Remove(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IDataDictionary{TKey,TValue}.Clear"/>
|
||||
public void Clear() => _dictionary.Clear();
|
||||
|
||||
/// <inheritdoc cref="IDataDictionary{TKey,TValue}.ContainsKey"/>
|
||||
public bool ContainsKey(TKey key)
|
||||
{
|
||||
// _dictionary.ContainsKey will take care of throwing on a null key.
|
||||
return _dictionary.ContainsKey(key);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="ConcurrentDictionary{TKey,TValue}.GetOrAdd(TKey,TValue)"/>
|
||||
public TValue? GetOrAdd(TKey key, TValue value)
|
||||
{
|
||||
// _dictionary.TryGetValue will take care of throwing on a null key.
|
||||
if (_dictionary.TryGetValue(key, out var result))
|
||||
return result;
|
||||
|
||||
if (value == null)
|
||||
return null;
|
||||
|
||||
_dictionary.Add(key, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IDictionary{TKey,TValue}.Remove(TKey)"/>
|
||||
public bool Remove(TKey key)
|
||||
{
|
||||
// _dictionary.Remove will take care of throwing on a null key.
|
||||
return _dictionary.Remove(key);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="ConcurrentDictionary{TKey,TValue}.TryAdd"/>
|
||||
public bool TryAdd(TKey key, TValue value)
|
||||
{
|
||||
// _dictionary.ContainsKey will take care of throwing on a null key.
|
||||
if (_dictionary.ContainsKey(key))
|
||||
return false;
|
||||
|
||||
if (value != null)
|
||||
_dictionary.Add(key, value);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IDataDictionary{TKey,TValue}.TryGetValue"/>
|
||||
public bool TryGetValue(TKey key, out TValue value) => _dictionary.TryGetValue(key, out value);
|
||||
|
||||
/// <inheritdoc cref="IDataDictionary{TKey,TValue}.TryRemove"/>
|
||||
public bool TryRemove(TKey key, out TValue value)
|
||||
{
|
||||
// TryGetValue will take care of throwing on a null key.
|
||||
if (!_dictionary.TryGetValue(key, out value))
|
||||
return false;
|
||||
|
||||
_dictionary.Remove(key);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="ConcurrentDictionary{TKey,TValue}.TryUpdate"/>
|
||||
public bool TryUpdate(TKey key, TValue newValue, TValue comparisonValue)
|
||||
{
|
||||
// TryGetValue will take care of throwing on a null key.
|
||||
if (!_dictionary.TryGetValue(key, out var value))
|
||||
return false;
|
||||
|
||||
if (value != comparisonValue)
|
||||
return false;
|
||||
|
||||
_dictionary[key] = newValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Implementation of IDictionary<TKey, TValue>
|
||||
|
||||
/// <inheritdoc cref="IDictionary{TKey,TValue}.Add(TKey,TValue)"/>
|
||||
void IDictionary<TKey, TValue>.Add(TKey key, TValue value)
|
||||
{
|
||||
// Validating the key seems redundant, because both Add and Remove
|
||||
// will throw on a null key.
|
||||
// This way, though, the code path on null key does not depend on value.
|
||||
// Without this validation, there should be two unit tests for null key,
|
||||
// one with a null value and one with a non-null value,
|
||||
// which makes no sense.
|
||||
if (key == null)
|
||||
throw new ArgumentNullException(nameof(key));
|
||||
|
||||
if (value != null)
|
||||
{
|
||||
_dictionary.Add(key, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
_dictionary.Remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Implementation of IReadOnlyDictionary<TKey, TValue>
|
||||
|
||||
/// <inheritdoc cref="IReadOnlyDictionary{TKey,TValue}.Keys"/>
|
||||
IEnumerable<TKey> IReadOnlyDictionary<TKey, TValue>.Keys => _dictionary.Keys;
|
||||
|
||||
/// <inheritdoc cref="IReadOnlyDictionary{TKey,TValue}.Values"/>
|
||||
IEnumerable<TValue> IReadOnlyDictionary<TKey, TValue>.Values => _dictionary.Values;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Implementation of ICollection<KeyValuePair<TKey, TValue>>
|
||||
|
||||
/// <inheritdoc cref="ICollection{T}.IsReadOnly"/>
|
||||
/// <remarks>
|
||||
/// <para>This property is always <see langword="false"/> for a <see cref="DataDictionary{TKey,TValue}"/>.</para>
|
||||
/// </remarks>
|
||||
bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly => false;
|
||||
|
||||
/// <inheritdoc cref="ICollection{T}.Add"/>
|
||||
void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)
|
||||
{
|
||||
if (item.Value != null)
|
||||
{
|
||||
((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).Add(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
_dictionary.Remove(item.Key);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="ICollection{T}.Contains"/>
|
||||
bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)
|
||||
=> ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).Contains(item);
|
||||
|
||||
/// <inheritdoc cref="ICollection{T}.CopyTo"/>
|
||||
void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
|
||||
=> ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).CopyTo(array, arrayIndex);
|
||||
|
||||
/// <inheritdoc cref="ICollection{T}.Remove"/>
|
||||
bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
|
||||
=> ((ICollection<KeyValuePair<TKey, TValue>>) _dictionary).Remove(item);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Implementation of IEnumerable<KeyValuePair<TKey, TValue>>
|
||||
|
||||
/// <inheritdoc cref="IEnumerable{T}.GetEnumerator"/>
|
||||
IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator() => _dictionary.GetEnumerator();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Implementation of IEnumerable
|
||||
|
||||
/// <inheritdoc cref="IEnumerable.GetEnumerator"/>
|
||||
IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)_dictionary).GetEnumerator();
|
||||
|
||||
#endregion
|
||||
}
|
||||
/// <see cref="Dictionary{TKey,TValue}()"/>
|
||||
public DataDictionary() => this._dictionary = new Dictionary<TKey, TValue>();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DataDictionary{TKey,TValue}"/> class
|
||||
/// that contains elements copied from the specified <see cref="IEnumerable{T}"/>,
|
||||
/// has the default initial capacity, and uses the default comparer for <typeparamref name="TKey"/>.
|
||||
/// </summary>
|
||||
/// <param name="collection">The <see cref="IEnumerable{T}"/> whose elements are copied
|
||||
/// to the new <see cref="DataDictionary{TKey,TValue}"/>.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="collection"/> is <see langword="null"/>.</exception>
|
||||
/// <remarks>
|
||||
/// <para>Since <see cref="DataDictionary{TKey,TValue}"/> does not store null values,
|
||||
/// key/value pairs whose value is <see langword="null"/> will not be copied from <paramref name="collection"/>.</para>
|
||||
/// </remarks>
|
||||
/// <see cref="Dictionary{TKey,TValue}()"/>
|
||||
public DataDictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection) {
|
||||
if(collection == null) {
|
||||
throw new ArgumentNullException(nameof(collection));
|
||||
}
|
||||
|
||||
this._dictionary = new Dictionary<TKey, TValue>();
|
||||
foreach(KeyValuePair<TKey, TValue> pair in collection.Where(pair => pair.Value != null)) {
|
||||
this._dictionary.Add(pair.Key, pair.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DataDictionary{TKey,TValue}"/> class
|
||||
/// that is empty, has the default capacity, and uses the specified <see cref="IEqualityComparer{T}"/>.
|
||||
/// </summary>
|
||||
/// <param name="comparer">The equality comparison implementation to use when comparing keys.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="comparer"/> is <see langword="null"/>.</exception>
|
||||
/// <see cref="Dictionary{TKey,TValue}(IEqualityComparer{TKey})"/>
|
||||
public DataDictionary(IEqualityComparer<TKey> comparer) => this._dictionary = new Dictionary<TKey, TValue>(comparer);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DataDictionary{TKey, TValue}"/> class
|
||||
/// that contains elements copied from the specified <see cref="IEnumerable{T}"/>,
|
||||
/// has the default initial capacity, and uses the specified <see cref="IEqualityComparer{T}"/>.
|
||||
/// </summary>
|
||||
/// <param name="collection">The <see cref="IEnumerable{T}"/> whose elements are copied
|
||||
/// to the new <see cref="DataDictionary{TKey,TValue}"/>.</param>
|
||||
/// <param name="comparer">The equality comparison implementation to use when comparing keys.</param>
|
||||
/// <remarks>
|
||||
/// <para>Since <see cref="DataDictionary{TKey,TValue}"/> does not store null values,
|
||||
/// key/value pairs whose value is <see langword="null"/> will not be copied from <paramref name="collection"/>.</para>
|
||||
/// </remarks>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <para><paramref name="collection"/> is <see langword="null"/>.</para>
|
||||
/// <para>- or -.</para>
|
||||
/// <para><paramref name="comparer"/> is <see langword="null"/>.</para>
|
||||
/// </exception>
|
||||
/// <see cref="Dictionary{TKey,TValue}(IEqualityComparer{TKey})"/>
|
||||
public DataDictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection, IEqualityComparer<TKey> comparer) {
|
||||
if(collection == null) {
|
||||
throw new ArgumentNullException(nameof(collection));
|
||||
}
|
||||
|
||||
this._dictionary = new Dictionary<TKey, TValue>(comparer);
|
||||
foreach(KeyValuePair<TKey, TValue> pair in collection.Where(pair => pair.Value != null)) {
|
||||
this._dictionary.Add(pair.Key, pair.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DataDictionary{TKey, TValue}"/> class
|
||||
/// that is empty, has the specified capacity, and uses the default comparer for the key type.
|
||||
/// </summary>
|
||||
/// <param name="capacity">The initial number of elements that the <see cref="DataDictionary{TKey, TValue}"/> can contain.</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException"><paramref name="capacity"/> is less than 0.</exception>
|
||||
/// <see cref="Dictionary{TKey,TValue}(Int32)"/>
|
||||
public DataDictionary(Int32 capacity) => this._dictionary = new Dictionary<TKey, TValue>(capacity);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DataDictionary{TKey, TValue}"/> class
|
||||
/// that contains elements copied from the specified <see cref="IEnumerable{T}"/>,
|
||||
/// has the specified capacity, and uses the specified <see cref="IEqualityComparer{T}"/>.
|
||||
/// </summary>
|
||||
/// <param name="capacity">The initial number of elements that the <see cref="DataDictionary{TKey, TValue}"/> can contain.</param>
|
||||
/// <param name="collection">The <see cref="IEnumerable{T}"/> whose elements are copied
|
||||
/// to the new <see cref="ConcurrentDataDictionary{TKey,TValue}"/>.</param>
|
||||
/// <param name="comparer">The equality comparison implementation to use when comparing keys.</param>
|
||||
/// <remarks>
|
||||
/// <para>Since <see cref="ConcurrentDataDictionary{TKey,TValue}"/> does not store null values,
|
||||
/// key/value pairs whose value is <see langword="null"/> will not be copied from <paramref name="collection"/>.</para>
|
||||
/// </remarks>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <para><paramref name="collection"/> is <see langword="null"/>.</para>
|
||||
/// <para>- or -.</para>
|
||||
/// <para><paramref name="comparer"/> is <see langword="null"/>.</para>
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException"><paramref name="capacity"/> is less than 0.</exception>
|
||||
/// <see cref="Dictionary{TKey,TValue}(Int32,IEqualityComparer{TKey})"/>
|
||||
public DataDictionary(Int32 capacity, IEnumerable<KeyValuePair<TKey, TValue>> collection, IEqualityComparer<TKey> comparer) {
|
||||
if(collection == null) {
|
||||
throw new ArgumentNullException(nameof(collection));
|
||||
}
|
||||
|
||||
this._dictionary = new Dictionary<TKey, TValue>(capacity, comparer);
|
||||
foreach(KeyValuePair<TKey, TValue> pair in collection.Where(pair => pair.Value != null)) {
|
||||
this._dictionary.Add(pair.Key, pair.Value);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public APIs
|
||||
|
||||
/// <inheritdoc cref="IDataDictionary{TKey,TValue}.Count"/>
|
||||
public Int32 Count => this._dictionary.Count;
|
||||
|
||||
/// <inheritdoc cref="IDataDictionary{TKey,TValue}.IsEmpty"/>
|
||||
public Boolean IsEmpty => this._dictionary.Count == 0;
|
||||
|
||||
/// <inheritdoc cref="IDictionary{TKey,TValue}.Keys"/>
|
||||
public ICollection<TKey> Keys => this._dictionary.Keys;
|
||||
|
||||
/// <inheritdoc cref="IDictionary{TKey,TValue}.Values"/>
|
||||
public ICollection<TValue> Values => this._dictionary.Values;
|
||||
|
||||
/// <inheritdoc cref="IDataDictionary{TKey,TValue}.this"/>
|
||||
public TValue this[TKey key] {
|
||||
get => this._dictionary.TryGetValue(key ?? throw new ArgumentNullException(nameof(key)), out TValue value) ? value : null;
|
||||
set {
|
||||
if(value != null) {
|
||||
this._dictionary[key] = value;
|
||||
} else {
|
||||
_ = this._dictionary.Remove(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IDataDictionary{TKey,TValue}.Clear"/>
|
||||
public void Clear() => this._dictionary.Clear();
|
||||
|
||||
/// <inheritdoc cref="IDataDictionary{TKey,TValue}.ContainsKey"/>
|
||||
public Boolean ContainsKey(TKey key) =>
|
||||
// _dictionary.ContainsKey will take care of throwing on a null key.
|
||||
this._dictionary.ContainsKey(key);
|
||||
|
||||
/// <inheritdoc cref="ConcurrentDictionary{TKey,TValue}.GetOrAdd(TKey,TValue)"/>
|
||||
public TValue GetOrAdd(TKey key, TValue value) {
|
||||
// _dictionary.TryGetValue will take care of throwing on a null key.
|
||||
if(this._dictionary.TryGetValue(key, out TValue result)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if(value == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
this._dictionary.Add(key, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IDictionary{TKey,TValue}.Remove(TKey)"/>
|
||||
public Boolean Remove(TKey key) =>
|
||||
// _dictionary.Remove will take care of throwing on a null key.
|
||||
this._dictionary.Remove(key);
|
||||
|
||||
/// <inheritdoc cref="ConcurrentDictionary{TKey,TValue}.TryAdd"/>
|
||||
public Boolean TryAdd(TKey key, TValue value) {
|
||||
// _dictionary.ContainsKey will take care of throwing on a null key.
|
||||
if(this._dictionary.ContainsKey(key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(value != null) {
|
||||
this._dictionary.Add(key, value);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IDataDictionary{TKey,TValue}.TryGetValue"/>
|
||||
public Boolean TryGetValue(TKey key, out TValue value) => this._dictionary.TryGetValue(key, out value);
|
||||
|
||||
/// <inheritdoc cref="IDataDictionary{TKey,TValue}.TryRemove"/>
|
||||
public Boolean TryRemove(TKey key, out TValue value) {
|
||||
// TryGetValue will take care of throwing on a null key.
|
||||
if(!this._dictionary.TryGetValue(key, out value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_ = this._dictionary.Remove(key);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="ConcurrentDictionary{TKey,TValue}.TryUpdate"/>
|
||||
public Boolean TryUpdate(TKey key, TValue newValue, TValue comparisonValue) {
|
||||
// TryGetValue will take care of throwing on a null key.
|
||||
if(!this._dictionary.TryGetValue(key, out TValue value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(value != comparisonValue) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this._dictionary[key] = newValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Implementation of IDictionary<TKey, TValue>
|
||||
|
||||
/// <inheritdoc cref="IDictionary{TKey,TValue}.Add(TKey,TValue)"/>
|
||||
void IDictionary<TKey, TValue>.Add(TKey key, TValue value) {
|
||||
// Validating the key seems redundant, because both Add and Remove
|
||||
// will throw on a null key.
|
||||
// This way, though, the code path on null key does not depend on value.
|
||||
// Without this validation, there should be two unit tests for null key,
|
||||
// one with a null value and one with a non-null value,
|
||||
// which makes no sense.
|
||||
if(key == null) {
|
||||
throw new ArgumentNullException(nameof(key));
|
||||
}
|
||||
|
||||
if(value != null) {
|
||||
this._dictionary.Add(key, value);
|
||||
} else {
|
||||
_ = this._dictionary.Remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Implementation of IReadOnlyDictionary<TKey, TValue>
|
||||
|
||||
/// <inheritdoc cref="IReadOnlyDictionary{TKey,TValue}.Keys"/>
|
||||
IEnumerable<TKey> IReadOnlyDictionary<TKey, TValue>.Keys => this._dictionary.Keys;
|
||||
|
||||
/// <inheritdoc cref="IReadOnlyDictionary{TKey,TValue}.Values"/>
|
||||
IEnumerable<TValue> IReadOnlyDictionary<TKey, TValue>.Values => this._dictionary.Values;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Implementation of ICollection<KeyValuePair<TKey, TValue>>
|
||||
|
||||
/// <inheritdoc cref="ICollection{T}.IsReadOnly"/>
|
||||
/// <remarks>
|
||||
/// <para>This property is always <see langword="false"/> for a <see cref="DataDictionary{TKey,TValue}"/>.</para>
|
||||
/// </remarks>
|
||||
Boolean ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly => false;
|
||||
|
||||
/// <inheritdoc cref="ICollection{T}.Add"/>
|
||||
void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item) {
|
||||
if(item.Value != null) {
|
||||
((ICollection<KeyValuePair<TKey, TValue>>)this._dictionary).Add(item);
|
||||
} else {
|
||||
_ = this._dictionary.Remove(item.Key);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="ICollection{T}.Contains"/>
|
||||
Boolean ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item) => ((ICollection<KeyValuePair<TKey, TValue>>)this._dictionary).Contains(item);
|
||||
|
||||
/// <inheritdoc cref="ICollection{T}.CopyTo"/>
|
||||
void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, Int32 arrayIndex) => ((ICollection<KeyValuePair<TKey, TValue>>)this._dictionary).CopyTo(array, arrayIndex);
|
||||
|
||||
/// <inheritdoc cref="ICollection{T}.Remove"/>
|
||||
Boolean ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item) => ((ICollection<KeyValuePair<TKey, TValue>>)this._dictionary).Remove(item);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Implementation of IEnumerable<KeyValuePair<TKey, TValue>>
|
||||
|
||||
/// <inheritdoc cref="IEnumerable{T}.GetEnumerator"/>
|
||||
IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator() => this._dictionary.GetEnumerator();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Implementation of IEnumerable
|
||||
|
||||
/// <inheritdoc cref="IEnumerable.GetEnumerator"/>
|
||||
IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)this._dictionary).GetEnumerator();
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,49 +1,46 @@
|
||||
using System;
|
||||
|
||||
namespace Swan.Collections
|
||||
{
|
||||
namespace Swan.Collections {
|
||||
/// <summary>
|
||||
/// <para>Implements a collection of components that automatically disposes each component
|
||||
/// implementing <see cref="IDisposable"/>.</para>
|
||||
/// <para>Each component in the collection may be given a unique name for later retrieval.</para>
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of components in the collection.</typeparam>
|
||||
/// <seealso cref="ComponentCollection{T}" />
|
||||
/// <seealso cref="IComponentCollection{T}" />
|
||||
public class DisposableComponentCollection<T> : ComponentCollection<T>, IDisposable {
|
||||
/// <summary>
|
||||
/// <para>Implements a collection of components that automatically disposes each component
|
||||
/// implementing <see cref="IDisposable"/>.</para>
|
||||
/// <para>Each component in the collection may be given a unique name for later retrieval.</para>
|
||||
/// Finalizes an instance of the <see cref="DisposableComponentCollection{T}"/> class.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of components in the collection.</typeparam>
|
||||
/// <seealso cref="ComponentCollection{T}" />
|
||||
/// <seealso cref="IComponentCollection{T}" />
|
||||
public class DisposableComponentCollection<T> : ComponentCollection<T>, IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Finalizes an instance of the <see cref="DisposableComponentCollection{T}"/> class.
|
||||
/// </summary>
|
||||
~DisposableComponentCollection()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases unmanaged and - optionally - managed resources.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases unmanaged and - optionally - managed resources.
|
||||
/// </summary>
|
||||
/// <param name="disposing">
|
||||
/// <see langword="true"/> to release both managed and unmanaged resources; <see langword="true"/> to release only unmanaged resources.
|
||||
/// </param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposing) return;
|
||||
|
||||
foreach (var component in this)
|
||||
{
|
||||
if (component is IDisposable disposable)
|
||||
disposable.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
~DisposableComponentCollection() {
|
||||
this.Dispose(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases unmanaged and - optionally - managed resources.
|
||||
/// </summary>
|
||||
public void Dispose() {
|
||||
this.Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases unmanaged and - optionally - managed resources.
|
||||
/// </summary>
|
||||
/// <param name="disposing">
|
||||
/// <see langword="true"/> to release both managed and unmanaged resources; <see langword="true"/> to release only unmanaged resources.
|
||||
/// </param>
|
||||
protected virtual void Dispose(Boolean disposing) {
|
||||
if(!disposing) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach(T component in this) {
|
||||
if(component is IDisposable disposable) {
|
||||
disposable.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,54 +1,56 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Swan.Collections
|
||||
{
|
||||
namespace Swan.Collections {
|
||||
/// <summary>
|
||||
/// <para>Represents a collection of components.</para>
|
||||
/// <para>Each component in the collection may be given a unique name for later retrieval.</para>
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of components in the collection.</typeparam>
|
||||
public interface IComponentCollection<T> : IReadOnlyList<T> {
|
||||
/// <summary>
|
||||
/// <para>Represents a collection of components.</para>
|
||||
/// <para>Each component in the collection may be given a unique name for later retrieval.</para>
|
||||
/// Gets an <see cref="IReadOnlyDictionary{TKey,TValue}"/> interface representing the named components.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of components in the collection.</typeparam>
|
||||
public interface IComponentCollection<T> : IReadOnlyList<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets an <see cref="IReadOnlyDictionary{TKey,TValue}"/> interface representing the named components.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The named components.
|
||||
/// </value>
|
||||
IReadOnlyDictionary<string, T> Named { get; }
|
||||
|
||||
/// <summary>
|
||||
/// <para>Gets an <see cref="IReadOnlyList{T}"/> interface representing all components
|
||||
/// associated with safe names.</para>
|
||||
/// <para>The safe name of a component is never <see langword="null"/>.
|
||||
/// If a component's unique name if <see langword="null"/>, its safe name
|
||||
/// will be some non-<see langword="null"/> string somehow identifying it.</para>
|
||||
/// <para>Note that safe names are not necessarily unique.</para>
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A list of <see cref="ValueTuple{T1,T2}"/>s, each containing a safe name and a component.
|
||||
/// </value>
|
||||
IReadOnlyList<(string SafeName, T Component)> WithSafeNames { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the component with the specified name.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The component.
|
||||
/// </value>
|
||||
/// <param name="name">The name.</param>
|
||||
/// <returns>The component with the specified <paramref name="name"/>.</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="name"/> is null.</exception>
|
||||
/// <exception cref="KeyNotFoundException">The property is retrieved and <paramref name="name"/> is not found.</exception>
|
||||
T this[string name] { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Adds a component to the collection,
|
||||
/// giving it the specified <paramref name="name"/> if it is not <see langword="null"/>.
|
||||
/// </summary>
|
||||
/// <param name="name">The name given to the module, or <see langword="null"/>.</param>
|
||||
/// <param name="component">The component.</param>
|
||||
void Add(string name, T component);
|
||||
}
|
||||
/// <value>
|
||||
/// The named components.
|
||||
/// </value>
|
||||
IReadOnlyDictionary<String, T> Named {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <para>Gets an <see cref="IReadOnlyList{T}"/> interface representing all components
|
||||
/// associated with safe names.</para>
|
||||
/// <para>The safe name of a component is never <see langword="null"/>.
|
||||
/// If a component's unique name if <see langword="null"/>, its safe name
|
||||
/// will be some non-<see langword="null"/> string somehow identifying it.</para>
|
||||
/// <para>Note that safe names are not necessarily unique.</para>
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A list of <see cref="ValueTuple{T1,T2}"/>s, each containing a safe name and a component.
|
||||
/// </value>
|
||||
IReadOnlyList<(String SafeName, T Component)> WithSafeNames {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the component with the specified name.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The component.
|
||||
/// </value>
|
||||
/// <param name="name">The name.</param>
|
||||
/// <returns>The component with the specified <paramref name="name"/>.</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="name"/> is null.</exception>
|
||||
/// <exception cref="KeyNotFoundException">The property is retrieved and <paramref name="name"/> is not found.</exception>
|
||||
T this[String name] { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Adds a component to the collection,
|
||||
/// giving it the specified <paramref name="name"/> if it is not <see langword="null"/>.
|
||||
/// </summary>
|
||||
/// <param name="name">The name given to the module, or <see langword="null"/>.</param>
|
||||
/// <param name="component">The component.</param>
|
||||
void Add(String name, T component);
|
||||
}
|
||||
}
|
||||
@@ -1,34 +1,32 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Swan.Collections
|
||||
{
|
||||
namespace Swan.Collections {
|
||||
/// <summary>
|
||||
/// Represents a generic collection of key/value pairs that does not store
|
||||
/// null values.
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey">The type of keys in the dictionary. This must be a reference type.</typeparam>
|
||||
/// <typeparam name="TValue">The type of values in the dictionary. This must be a reference type.</typeparam>
|
||||
public interface IDataDictionary<TKey, TValue> : IDictionary<TKey, TValue>, IReadOnlyDictionary<TKey, TValue> where TKey : class where TValue : class {
|
||||
/// <summary>
|
||||
/// Represents a generic collection of key/value pairs that does not store
|
||||
/// null values.
|
||||
/// Gets a value that indicates whether the <see cref="IDataDictionary{TKey,TValue}"/> is empty.
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey">The type of keys in the dictionary. This must be a reference type.</typeparam>
|
||||
/// <typeparam name="TValue">The type of values in the dictionary. This must be a reference type.</typeparam>
|
||||
public interface IDataDictionary<TKey, TValue> : IDictionary<TKey, TValue>, IReadOnlyDictionary<TKey, TValue>
|
||||
where TKey : class
|
||||
where TValue : class
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a value that indicates whether the <see cref="IDataDictionary{TKey,TValue}"/> is empty.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <see langword="true"/> if the <see cref="IDataDictionary{TKey,TValue}"/> is empty; otherwise, <see langword="false"/>.
|
||||
/// </value>
|
||||
bool IsEmpty { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to remove and return the value that has the specified key from the <see cref="IDataDictionary{TKey,TValue}"/>.
|
||||
/// </summary>
|
||||
/// <param name="key">The key of the element to remove and return.</param>
|
||||
/// <param name="value">When this method returns, the value removed from the <see cref="IDataDictionary{TKey,TValue}"/>,
|
||||
/// if the key is found; otherwise, <see langword="null"/>. This parameter is passed uninitialized.</param>
|
||||
/// <returns><see langword="true"/> if the value was removed successfully; otherwise, <see langword="false"/>.</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="key"/> is <see langword="null"/>.</exception>
|
||||
bool TryRemove(TKey key, out TValue value);
|
||||
}
|
||||
/// <value>
|
||||
/// <see langword="true"/> if the <see cref="IDataDictionary{TKey,TValue}"/> is empty; otherwise, <see langword="false"/>.
|
||||
/// </value>
|
||||
Boolean IsEmpty {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to remove and return the value that has the specified key from the <see cref="IDataDictionary{TKey,TValue}"/>.
|
||||
/// </summary>
|
||||
/// <param name="key">The key of the element to remove and return.</param>
|
||||
/// <param name="value">When this method returns, the value removed from the <see cref="IDataDictionary{TKey,TValue}"/>,
|
||||
/// if the key is found; otherwise, <see langword="null"/>. This parameter is passed uninitialized.</param>
|
||||
/// <returns><see langword="true"/> if the value was removed successfully; otherwise, <see langword="false"/>.</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="key"/> is <see langword="null"/>.</exception>
|
||||
Boolean TryRemove(TKey key, out TValue value);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user