Thread-safe C# Dictionary class.
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Threading;
namespace TinyIoC
{
public class SafeDictionary<TKey, TValue> : IDisposable
{
private readonly ReaderWriterLockSlim _padlock = new ReaderWriterLockSlim();
private readonly Dictionary<TKey, TValue> _Dictionary = new Dictionary<TKey, TValue>();
public TValue this[TKey key]
{
set
{
_padlock.EnterWriteLock();
try
{
TValue current;
if (_Dictionary.TryGetValue(key, out current))
{
var disposable = current as IDisposable;
if (disposable != null)
disposable.Dispose();
}
_Dictionary[key] = value;
}
finally
{
_padlock.ExitWriteLock();
}
}
}
public bool TryGetValue(TKey key, out TValue value)
{
_padlock.EnterReadLock();
try
{
return _Dictionary.TryGetValue(key, out value);
}
finally
{
_padlock.ExitReadLock();
}
}
public bool Remove(TKey key)
{
_padlock.EnterWriteLock();
try
{
return _Dictionary.Remove(key);
}
finally
{
_padlock.ExitWriteLock();
}
}
public void Clear()
{
_padlock.EnterWriteLock();
try
{
_Dictionary.Clear();
}
finally
{
_padlock.ExitWriteLock();
}
}
public IEnumerable<TKey> Keys
{
get
{
_padlock.EnterReadLock();
try
{
return new List<TKey>(_Dictionary.Keys);
}
finally
{
_padlock.ExitReadLock();
}
}
}
public void Dispose()
{
_padlock.EnterWriteLock();
try
{
var disposableItems = from item in _Dictionary.Values
where item is IDisposable
select item as IDisposable;
foreach (var item in disposableItems)
{
item.Dispose();
}
}
finally
{
_padlock.ExitWriteLock();
}
GC.SuppressFinalize(this);
}
}
}
// ---------------------------------------------------------------------------------------------------------
// Another thread-safe generic dictionary class
// Source: https://github.com/madhatter22/LinqToLdap/blob/master/LinqToLdap/Collections/SafeDictionary.cs
// ---------------------------------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
namespace LinqToLdap.Collections
{
internal class SafeDictionary<TKey, TValue>
{
private ReaderWriterLockSlim _locker = new ReaderWriterLockSlim();
private Dictionary<TKey, TValue> _internal = new Dictionary<TKey, TValue>();
~SafeDictionary()
{
var locker = _locker;
if (locker != null)
{
locker.Dispose();
_locker = locker = null;
}
var dictionary = _internal;
if (dictionary != null)
{
dictionary.Clear();
_internal = dictionary = null;
}
}
public TValue GetOrAdd(TKey key, Func<TKey, TValue> valueFactory)
{
_locker.EnterReadLock();
try
{
if (_internal.ContainsKey(key))
{
return _internal[key];
}
}
finally
{
_locker.ExitReadLock();
}
var value = valueFactory(key);
_locker.EnterWriteLock();
try
{
if (!_internal.ContainsKey(key))
{
_internal.Add(key, value);
}
return _internal[key];
}
finally
{
_locker.ExitWriteLock();
}
}
public ReadOnlyDictionary<TKey, TValue> ToReadOnly()
{
_locker.EnterReadLock();
try
{
return new ReadOnlyDictionary<TKey, TValue>(_internal.ToDictionary(d => d.Key, d => d.Value));
}
finally
{
_locker.ExitReadLock();
}
}
public bool TryGetValue(TKey key, out TValue value)
{
_locker.EnterReadLock();
try
{
if (_internal.ContainsKey(key))
{
value = _internal[key];
return true;
}
value = default;
return false;
}
finally
{
_locker.ExitReadLock();
}
}
public void TryAdd(TKey key, TValue value)
{
_locker.EnterWriteLock();
try
{
if (!_internal.ContainsKey(key))
{
_internal.Add(key, value);
}
}
finally
{
_locker.ExitWriteLock();
}
}
public void AddOrUpdate(TKey key, TValue value)
{
_locker.EnterWriteLock();
try
{
_internal[key] = value;
}
finally
{
_locker.ExitWriteLock();
}
}
}
}