ConcurrentDictionary works well for concurrent situations when mapping keys to a single value each. When mapping to multiple values, it is easy to create a ConcurrentDictionary<K, List<V>> and guard its addition/removal functions.
ConcurrentDictionary <string, List<string>> d;
// Add
var list = d.GetOrAdd ("key", x => new List<string> ());
lock (list) {
list.Add ("value to add");
}
// Remove
if (d.TryGetValue ("key", out var list)) {
lock (list) {
list.Remove ("value to remove");
}
}
However, the above assumed that empty lists are allowed to stay. I don't want that. But removing empty pairs does not seem to be possible in an atomic fashion. One might try:
if (d.TryGetValue ("key", out var list)) {
lock (list) {
if (list.Remove ("value to remove") && list.Count == 0) {
d.TryRemove ("key", out _);
}
}
}
But this has a race condition when another thread grabs the list before but adds to it after it was emptied and removed elsewhere:
A: get list
B: get list
B: lock, remove from list
B: list is empty, delete key, unlock
A: lock, add to list, unlock
Locking on the dictionary is not possible (it's a different use case).
As far as I can tell, a solution would usually be found using compare-and-swap operations and replacing the list with e.g. an immutable array that is then replaced in its entirety. However, given that ConcurrentDictionary does not offer a TryRemove with an expected value to compare against, I don't quite see how. Possibly there is a two-stage solution?
Using the out parameter of TryRemove to add values again after removing them (to fix race cases) is not possible - the dictionary would briefly be in an inconsistent state.
There are many questions on this site asking about similar scenarios, but most of them suffer from trivial mistakes or do not remove empty entries. There is this highly related question which asks if it is possible to do this. Sadly, it is five years old, received very little attention and has no solution apart from resorting to locks (which defeats the purpose). Possibly there opened up a better way since that time.
(Edited example for clarity)
I managed to implement a ConcurrentMultiDictionary class that stores multiple values per key, and with empty entries removed. The values of each key are stored in a HashSet, so each key has unique values. This increases the performance of deleting a value when the number of values is large. If the uniqueness is a problem then the HashSet should be replaced with a List, and the Add method should be modified to return void instead of bool.
The atomicity of the adding and removing operations is achieved by spinning. When a bag of values becomes empty, it is flagged as "discarded". Adding values into a discarded bag is not allowed, so the Add operation spins until it grabs a non discarded bag. The Remove operation spins too. So the only thread that is allowed to remove a discarded bag is the same thread that marked the bag as discarded. All other threads will be spinning until that happens. SpinWait structs are used for the spinning, to ensure efficiency even in single processor machines.
An unsolvable problem of this implementation is how to implement a ToArray method that takes a snapshot of all keys and values stored in the dictionary. The ConcurrentDictionary.ToArray method returns a snapshot of the keys, but the bags can be constantly changing, and this is why I believe it is unsolvable.
Even implementing the IEnumerable interface is a bit tricky, because if we just enumerate the KeyValuePairs of the underlying dictionary, most of the bags could be discarded at the time their values are acquired. So during the enumeration the bag of each key is retrieved individually, to be as current as possible.
public class ConcurrentMultiDictionary<TKey, TValue>
: IEnumerable<KeyValuePair<TKey, TValue[]>>
{
private class Bag : HashSet<TValue>
{
public bool IsDiscarded { get; set; }
}
private readonly ConcurrentDictionary<TKey, Bag> _dictionary;
public ConcurrentMultiDictionary()
{
_dictionary = new ConcurrentDictionary<TKey, Bag>();
}
public int Count => _dictionary.Count;
public bool Add(TKey key, TValue value)
{
var spinWait = new SpinWait();
while (true)
{
var bag = _dictionary.GetOrAdd(key, _ => new Bag());
lock (bag)
{
if (!bag.IsDiscarded) return bag.Add(value);
}
spinWait.SpinOnce();
}
}
public bool Remove(TKey key, TValue value)
{
var spinWait = new SpinWait();
while (true)
{
if (!_dictionary.TryGetValue(key, out var bag)) return false;
bool spinAndRetry = false;
lock (bag)
{
if (bag.IsDiscarded)
{
spinAndRetry = true;
}
else
{
bool valueRemoved = bag.Remove(value);
if (!valueRemoved) return false;
if (bag.Count != 0) return true;
bag.IsDiscarded = true;
}
}
if (spinAndRetry) { spinWait.SpinOnce(); continue; }
bool keyRemoved = _dictionary.TryRemove(key, out var currentBag);
Debug.Assert(keyRemoved, $"Key {key} was not removed");
Debug.Assert(bag == currentBag, $"Removed wrong bag");
return true;
}
}
public bool TryGetValues(TKey key, out TValue[] values)
{
if (!_dictionary.TryGetValue(key, out var bag)) { values = null; return false; }
bool isDiscarded;
lock (bag) { isDiscarded = bag.IsDiscarded; values = bag.ToArray(); }
if (isDiscarded) { values = null; return false; }
return true;
}
public bool Contains(TKey key, TValue value)
{
if (!_dictionary.TryGetValue(key, out var bag)) return false;
lock (bag) return !bag.IsDiscarded && bag.Contains(value);
}
public bool ContainsKey(TKey key) => _dictionary.ContainsKey(key);
public ICollection<TKey> Keys => _dictionary.Keys;
public IEnumerator<KeyValuePair<TKey, TValue[]>> GetEnumerator()
{
foreach (var key in _dictionary.Keys)
{
if (this.TryGetValues(key, out var values))
{
yield return new KeyValuePair<TKey, TValue[]>(key, values);
}
}
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
This implementation was tested with 8 concurrent workers mutating a dictionary a million times per worker, and no inconsistency regarding the reported number of additions and removals was observed.
There seems to be no practical way of removing an empty collection (even if it is synchronized) from a concurrent dictionary without having race condition issues. There are certain facts preventing this from being possible, as discussed in the comments under both the question and the OP's self answer.
What I wrote in my comment, however, seemed feasible and I wanted to give it a try.
I want to discuss the drawbacks of this implementation right after, and I should also say that your comments (if received any) are what is most valuable to me.
First, the usage:
static void Main(string[] args)
{
var myDictionary = new ConcurrentDictionary<string, IList<int>>();
IList<int> myList = myDictionary.AddSelfRemovingList<string, int>("myList");
myList.Add(5);
myList.Add(6);
myList.Remove(6);
myList.Remove(5);
IList<int> existingInstance;
// returns false:
bool exists = myDictionary.TryGetValue("myList", out existingInstance);
// throws HasAlreadyRemovedSelfException:
myList.Add(3);
}
AddSelfRemovingList is an extension method to make things easier.
For the discussion part:
It is not acceptable for the removal of an item from a collection to have a side effect of removing the collection reference from the owning dictionary.
It is also not good practice to make the collection obsolete (unusable) when all its items are removed. There is a strong possibility that the consumer of the collection wants to clear and re-fill the collection and this implementation does not allow that.
It forces the use of IList<T> abstraction and a custom implementation over List<T>
Although this provides a real thread-safe way of removing a just emptied collection from the dictionary, there seem to be more cons than pros to it. This should only be used in a closed context where the collections inside the concurrent dictionary are exposed to the outside, and where the immediate removal of a collection when emptied, even if some other thread is accessing it at the moment, is essential.
Here is the extension method to create and add the self removing list to the dictionary:
public static class ConcurrentDictionaryExtensions
{
public static IList<TValue> AddSelfRemovingList<TKey, TValue>(this ConcurrentDictionary<TKey, IList<TValue>> dictionaryInstance, TKey key)
{
var newInstance = new SelfRemovingConcurrentList<TKey, TValue>(dictionaryInstance, key);
if (!dictionaryInstance.TryAdd(key, newInstance))
{
throw new ArgumentException("ownerAccessKey", "The passed ownerAccessKey has already exist in the parent dictionary");
}
return newInstance;
}
}
And finally; here is the synchronized, self-removing implementation of IList<T>:
public class SelfRemovingConcurrentList<TKey, TValue> : IList<TValue>
{
private ConcurrentDictionary<TKey, IList<TValue>> owner;
private TKey ownerAccessKey;
List<TValue> underlyingList = new List<TValue>();
private bool hasRemovedSelf;
public class HasAlreadyRemovedSelfException : Exception
{
}
internal SelfRemovingConcurrentList(ConcurrentDictionary<TKey, IList<TValue>> owner, TKey ownerAccessKey)
{
this.owner = owner;
this.ownerAccessKey = ownerAccessKey;
}
private void ThrowIfHasAlreadyRemovedSelf()
{
if (hasRemovedSelf)
{
throw new HasAlreadyRemovedSelfException();
}
}
[MethodImpl(MethodImplOptions.Synchronized)]
int IList<TValue>.IndexOf(TValue item)
{
ThrowIfHasAlreadyRemovedSelf();
return underlyingList.IndexOf(item);
}
[MethodImpl(MethodImplOptions.Synchronized)]
void IList<TValue>.Insert(int index, TValue item)
{
ThrowIfHasAlreadyRemovedSelf();
underlyingList.Insert(index, item);
}
[MethodImpl(MethodImplOptions.Synchronized)]
void IList<TValue>.RemoveAt(int index)
{
ThrowIfHasAlreadyRemovedSelf();
underlyingList.RemoveAt(index);
if (underlyingList.Count == 0)
{
hasRemovedSelf = true;
IList<TValue> removedInstance;
if (!owner.TryRemove(ownerAccessKey, out removedInstance))
{
// Just ignore.
// What we want to do is to remove ourself from the owner (concurrent dictionary)
// and it seems like we have already been removed!
}
}
}
TValue IList<TValue>.this[int index]
{
[MethodImpl(MethodImplOptions.Synchronized)]
get
{
ThrowIfHasAlreadyRemovedSelf();
return underlyingList[index];
}
[MethodImpl(MethodImplOptions.Synchronized)]
set
{
ThrowIfHasAlreadyRemovedSelf();
underlyingList[index] = value;
}
}
[MethodImpl(MethodImplOptions.Synchronized)]
void ICollection<TValue>.Add(TValue item)
{
ThrowIfHasAlreadyRemovedSelf();
underlyingList.Add(item);
}
[MethodImpl(MethodImplOptions.Synchronized)]
void ICollection<TValue>.Clear()
{
ThrowIfHasAlreadyRemovedSelf();
underlyingList.Clear();
hasRemovedSelf = true;
IList<TValue> removedInstance;
if (!owner.TryRemove(ownerAccessKey, out removedInstance))
{
// Just ignore.
// What we want to do is to remove ourself from the owner (concurrent dictionary)
// and it seems like we have already been removed!
}
}
[MethodImpl(MethodImplOptions.Synchronized)]
bool ICollection<TValue>.Contains(TValue item)
{
ThrowIfHasAlreadyRemovedSelf();
return underlyingList.Contains(item);
}
[MethodImpl(MethodImplOptions.Synchronized)]
void ICollection<TValue>.CopyTo(TValue[] array, int arrayIndex)
{
ThrowIfHasAlreadyRemovedSelf();
underlyingList.CopyTo(array, arrayIndex);
}
int ICollection<TValue>.Count
{
[MethodImpl(MethodImplOptions.Synchronized)]
get
{
ThrowIfHasAlreadyRemovedSelf();
return underlyingList.Count;
}
}
bool ICollection<TValue>.IsReadOnly
{
[MethodImpl(MethodImplOptions.Synchronized)]
get
{
ThrowIfHasAlreadyRemovedSelf();
return false;
}
}
[MethodImpl(MethodImplOptions.Synchronized)]
bool ICollection<TValue>.Remove(TValue item)
{
ThrowIfHasAlreadyRemovedSelf();
bool removalResult = underlyingList.Remove(item);
if (underlyingList.Count == 0)
{
hasRemovedSelf = true;
IList<TValue> removedInstance;
if (!owner.TryRemove(ownerAccessKey, out removedInstance))
{
// Just ignore.
// What we want to do is to remove ourself from the owner (concurrent dictionary)
// and it seems like we have already been removed!
}
}
return removalResult;
}
[MethodImpl(MethodImplOptions.Synchronized)]
IEnumerator<TValue> IEnumerable<TValue>.GetEnumerator()
{
ThrowIfHasAlreadyRemovedSelf();
return underlyingList.GetEnumerator();
}
[MethodImpl(MethodImplOptions.Synchronized)]
IEnumerator IEnumerable.GetEnumerator()
{
ThrowIfHasAlreadyRemovedSelf();
return underlyingList.GetEnumerator();
}
}
The question can be solved by using a dictionary that offers a variant of TryRemove that first checks that the current value is equal to an expected value. Only if the values compare equal, the value is replaced (atomically). Otherwise, the operation returns failure.
It turns out ConcurrentDictionary already implements exactly this functionality:
/// <summary>
/// Removes the specified key from the dictionary if it exists and returns its associated value.
/// If matchValue flag is set, the key will be removed only if is associated with a particular
/// value.
/// </summary>
/// <param name="key">The key to search for and remove if it exists.</param>
/// <param name="value">The variable into which the removed value, if found, is stored.</param>
/// <param name="matchValue">Whether removal of the key is conditional on its value.</param>
/// <param name="oldValue">The conditional value to compare against if <paramref name="matchValue"/> is true</param>
/// <returns></returns>
private bool TryRemoveInternal(TKey key, out TValue value, bool matchValue, TValue oldValue)
TryRemove calls this (with matchValue set to false). The method is sadly not exposed (it is private). A simple solution would thus be to copy the existing class and change this method to be public. I'm not sure why it was not exposed. If the specific functionality were not working well, matchValue would most likely have been removed earlier.
As #Theodor Zoulias notes, it is also possible to invoke the private TryRemoveInternal method by using reflection. As far as I know, this can be done without major impact on performence.
There are also third party implementations with (claimed) high performance and concurrency that exhibit a TryRemove (..., expectedValue).
Once an implementation is chosen, the following code implements the asked for functionality. It uses the atomic compare-and-swap operations provided by the dictionary in a loop until it succeeds (similar to what many concurrent dictionaries do internally, too). As far as I'm aware, this is a typical approach in lock-free algorithms.
// Use any third-party dictionary that offers TryRemove() with
// a value to compare against (two are mentioned above)
ConcurrentDictionary<TKey, List<TValue>> d;
...
// To remove a value from key:
// Loop until the compare-and-swap of either update or removal succeeded
while (true)
{
// If the key does not exist, exit
if (!d.TryGetValue (key, out var list)) {
break;
}
// Remove the value from this key's entry:
// Consider the old value immutable, copy-and-modify it instead
List<TValue> newlist;
lock (list) {
newlist = list.Where (it => it != valueToRemove).ToList ();
}
// If the value list is not empty, compare-and-update it
if (newlist.Count > 0) {
if (d.TryUpdate (key: key, newValue: newlist, expectedValue: list)) {
return;
}
}
else // The key's value list is empty - compare-and-remove the entire key
{
// Remove the key iff the associated value is still the same
if (d.TryRemove (key: key, expectedValue: list)) { // Note that list is an in-, not an out-parameter
return;
}
}
// If we reach this point, the operation failed - try again
}
Related
Is there such a thing as a non-concurrent bag? I see lots of mentions of ConcurrentBag, but nothing about Bag.
Does such a collection exist?
To clarify why I'd like to use such a collection, I often find that the order of a collection becomes an important but potentially difficult to trace property of a collection.
I'm not necessarily saying that this would often happen in good, well designed code, but there are situations where I wish I could say "do not expect any order on this collection, order it specifically as and when you need to".
No, but since it documented as being "optimized for scenarios where the same thread will be both producing and consuming data stored in the bag", you can just use ConcurrentBag in both concurrent and non-concurrent scenarios.
You could always write your own class that "hides" the order of the items.
For example:
public sealed class NonConcurrentBag<T>: IReadOnlyCollection<T>
{
public void Add(T item)
{
// When adding an item, add it to a random location to avoid callers assuming an ordering.
if (_items.Count == 0)
{
_items.Add(item);
return;
}
int index = _rng.Next(0, _items.Count);
_items.Add(_items[index]);
_items[index] = item;
}
public void Clear()
{
_items.Clear();
}
public T Take()
{
if (_items.Count == 0)
throw new InvalidOperationException("Attempting to Take() from an empty NonConcurrentBag");
var result = _items[_items.Count - 1];
_items.RemoveAt(_items.Count - 1);
return result;
}
public bool IsEmpty => _items.Count == 0;
public IEnumerator<T> GetEnumerator()
{
return _items.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public int Count => _items.Count;
readonly List<T> _items = new List<T>();
readonly Random _rng = new Random();
}
When you add an item, this sneakily adds it at a random index (shifting the displaced item to the end of the list).
That means that not only is the index of an item random when you add it, it can also move to a different index as you add more items. That'll foil anything that expects any particular order!
Adding and taking items is an O(1) operation except when adding and the underlying list needs to be resized, when it is an O(N) operation.
This question already has answers here:
How to achieve remove_if functionality in .NET ConcurrentDictionary
(5 answers)
Closed 10 months ago.
The scenario I have is I want a method on ConcurrentDictionary like this.
bool TryRemove(TKey key, TValue value) {
// remove the value IF the value passed in == dictionary[key]
// return false if the key is not in the dictionary, or the value is not equal
}
Is there a way to do this concurrently? I'm struggling to find an answer for this scenario, even though it seems like this is a common use case.
I could do something like this, but I want to avoid a lock if I'm already using a ConcurrentDictionary. I'd also have to have locks on GetOrAdd() or AddOrUpdate() calls elsewhere. It just seems like there should be a better way with a ConcurrentDictionary.
ConcurrentDictionary<int, string> dict = ...;
/// stuff
int keyTryToRemove = 1337;
string valTryToRemove = "someValue";
bool success = false;
lock(keyTryToRemove) {
string val;
if (dict.TryRemove(keyTryToRemove, out val)) {
if (val == valTryToRemove) {
success = true;
}
else { // reinsert value, UGLY!
dict[keyTryToRemove] = val;
success = false;
}
} else {
success = false;
}
}
Since ConcurrentDictionary<TKey, TValue> class implements (although explicitly) IDictionary<TKey, TValue>, thus ICollection<KeyValuePair<TKey, TValue>>, you can simply cast it to the later and use Remove method like this:
bool success = ((ICollection<KeyValuePair<TKey, TValue>>)dict).Remove(
new KeyValuePair<TKey, TValue>(key, value));
The implementation internally uses the same thread safe method (passing additionally the value to be checked) as the public TryRemove method - exactly as it should be.
Edit: Generally speaking, the method in question can be made available for any type implementing IDictionary<TKey, TValue> (or more precisely ICollection<KeyValuePair<TKey, TValue>>) like Dictionary, ConcurrentDictionary etc. by introducing a custom extension method like this:
public static class Extensions
{
public static bool TryRemove<TKey, TValue>(this ICollection<KeyValuePair<TKey, TValue>> source, TKey key, TValue value)
{
return source.Remove(new KeyValuePair<TKey, TValue>(key, value));
}
}
so the sample code becomes simply:
bool success = dict.TryRemove(key, value);
I'd do something like this
bool success = false;
lock(lockForDictionary)
{
string val;
if (dict.TryGetValue(keyTryToRemove, out val) && val == valTryToRemove)
{
dict.Remove(keyTryToRemove);
success = true;
}
}
Below is a piece of code that simplify the steps a bit.
readonly object _locker = new object();
readonly ConcurrentDictionary<int, string> _dict = new ConcurrentDictionary<int, string>();
public bool TryRemove(int key, string value)
{
var success = false;
lock (_locker)
{
if (_dict.ContainsKey(key) && _dict[key] == value)
{
string val;
success = _dict.TryRemove(key, out val);
}
}
return success;
}
With that said, it seems the goal is non atomic in nature and this is why we have the need for a lock. It's important to ask, what is your goal and can you express the goal in an atomic way. 2 useful methods of ConcurrentDictionary include TryUpdate and AddOrUpdate. Would any of those methods help?
I have a C# class that acts as a dictionary so I'm now in the process of supporting IDictionary.
Everything is fine except for the properties Keys and Values:
ICollection<TKey> Keys { get; }
ICollection<TValue> Values { get; }
I don't have a collection of keys or values internally so I'm wondering how to provide these as a ICollection.
My first attempt was to use the magic of "yield return" like this:
ICollection<TValue> Values {
get {
for( int i = 0; i < nbValues; ++i ) {
yield return GetValue(i);
}
}
}
But of course this doesn't work since the returned type is not a IEnumerator but a ICollection...
It's too bad because this would have been the simplest solution !
My second attempt was to copy my values in a newly created array and return the array.
ICollection<TValue> Values {
get {
TValue[] copy = new TValue[nbValues];
for( int i = 0; i < nbValues; ++i ) {
copy[i] = GetValue(i);
}
return copy;
}
}
This would work since Array supports ICollection.
But the problem is that ICollection has methods to add and remove entries.
If the caller calls these methods only the copy will be modified not the dictionary...
The final solution I chose is to have my dictionary supports IDictionary but also ICollection and ICollection just so that I can return these collections from the properties Keys and Values...
public class MyDictionary : IDictionary<TKey,TValue>,
ICollection<TKey>,
ICollection<TValue>
{
}
So now the get accessor for the properties Keys and Values simply returns "this" ie: the dictionary.
ICollection<TValue> Values {
get {
return this;
}
}
It's probably the most optimal solution but I found it cumbersome to have to implement two extra interfaces whenever you want to implement IDictionary.
Do you have any other idea ?
I'm thinking that maybe returning the copy as an array was not such a bad idea after all. Anyway there is already a Add and Remove method in IDictionary which make more sense to be used.
Maybe returning a ReadOnlyCollection wrapping the array would be better as any attempt to modify the returned collection would fail?
ICollection<TValue> Values {
get {
TValue[] copy = new TValue[nbValues];
for( int i = 0; i < nbValues; ++i ) {
copy[i] = GetValue(i);
}
return new System.Collections.ObjectModel.ReadOnlyCollection<TValue>(copy);
}
}
I wouldn't personally expect you to be able to remove keys and values from a dictionary via Keys and Values anyway - I think it's fine to not do so.
Returning a ReadOnlyCollection<T> is fine - that waythe caller will just get an exception if they try to modify the collection, rather than the attempt just being silently ignored.
That exception follows the behaviour of Dictionary<TKey, TValue> by the way:
using System;
using System.Collections.Generic;
class Test
{
static void Main()
{
IDictionary<string, string> dictionary =
new Dictionary<string, string> {{ "a", "b" }};
dictionary.Keys.Clear();
Console.WriteLine(dictionary.Count);
}
}
Results:
Unhandled Exception: System.NotSupportedException: Mutating a key collection
derived from a dictionary is not allowed.
at System.Collections.Generic.Dictionary`2
.KeyCollection.System.Collections.Generic.ICollection<TKey>.Clear()
at Test.Main()
As SLaks says, if you can create your own implementation of ICollection<T> which is lazy, that would be better - but if that's tricky for some reason, or indeed if the performance isn't important in your case, just creating the array and wrapping it in ReadOnlyCollection<T> is fine. You should consider documenting the expected performance either way though.
One thing to note if you do create your own lazy implementation: you should probably have some sort of "version number" to make sure that you invalidate the returned collection if the underlying data is changed.
A ReadOnlyCollection is the best approach of the options you listed; these collections are not supposed to be writable.
However that your getter is O(n), which is not good.
The correct approach is to create your own collection classes that implement ICollection<T> and return a live view of the dictionary. (and throw exceptions from mutation methods)
This is the approach taken by Dictionary<TKey, TValue>; it ensures that the property getters are fast, and does not waste extra memory.
Thank you all for your answers.
So I ended up doing two utility classes that implement the two ICollection requested by the Keys and Values properties. I have a few dictionaries where I need to add support for IDictionary so I will be reusing them a few times:
Here is the class for the collection of keys:
public class ReadOnlyKeyCollectionFromDictionary< TDictionary, TKey, TValue >
: ICollection<TKey>
where TDictionary : IDictionary<TKey,TValue>, IEnumerable<TKey>
{
IDictionary<TKey, TValue> dictionary;
public ReadOnlyKeyCollectionFromDictionary(TDictionary inDictionary)
{
dictionary = inDictionary;
}
public bool IsReadOnly {
get { return true; }
}
Here I implement ICollection<TKey> by simply calling the corresponding method on
the member "dictionary" but I throw a NotSupportedException for the methods Add,
Remove and Clear
public IEnumerator<TKey> GetEnumerator()
{
return (dictionary as IEnumerable<TKey>).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return (dictionary as IEnumerable).GetEnumerator();
}
}
Here is the class for the collection of values:
public class ReadOnlyValueCollectionFromDictionary<TDictionary, TKey, TValue>
: ICollection<TValue>
where TDictionary : IDictionary<TKey, TValue>, IEnumerable<TValue>
{
IDictionary<TKey, TValue> dictionary;
public ReadOnlyValueCollectionFromDictionary(TDictionary inDictionary)
{
dictionary = inDictionary;
}
public bool IsReadOnly {
get { return true; }
}
Here I implement ICollection<TValue> by simply calling the corresponding method on
the member "dictionary" but I throw a NotSupportedException for the methods Add,
Remove and Clear
// I tried to support this one but I cannot compare a TValue with another TValue
// by using == since the compiler doesn't know if TValue is a struct or a class etc
// So either I add a generic constraint to only support classes (or ?) or I simply
// don't support this method since it's ackward in a dictionary anyway to search by
// value. Users can still do it themselves if they insist.
bool IEnumerable<TValue>.Contains(TValue value)
{
throw new System.NotSupportedException("A dictionary is not well suited to search by values");
}
public IEnumerator<TValue> GetEnumerator()
{
return (dictionary as IEnumerable<TValue>).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return (dictionary as IEnumerable).GetEnumerator();
}
}
Then if my dictionary supports the IEnumerable for TKey and TValue everything becomes so simple:
public class MyDictionary : IDictionary<SomeKey,SomeValue>,
IEnumerable<SomeKey>,
IEnumerable<SomeValue>
{
IEnumerator<SomeKey> IEnumerable<SomeKey>.GetEnumerator()
{
for ( int i = 0; i < nbElements; ++i )
{
yield return GetKeyAt(i);
}
}
IEnumerator<SomeValue> IEnumerable<SomeValue>.GetEnumerator()
{
for ( int i = 0; i < nbElements; ++i )
{
yield return GetValueAt(i);
}
}
// IEnumerator IEnumerable.GetEnumerator() is already implemented in the dictionary
public ICollection<SomeKey> Keys
{
get
{
return new ReadOnlyKeyCollectionFromDictionary< MyDictionary, SomeKey, SomeValue>(this);
}
}
public ICollection<Value> Values
{
get
{
return new ReadOnlyValueCollectionFromDictionary< MyDictionary, SomeKey, SomeValue >(this);
}
}
}
It's too bad IDictionary is not returning IEnumerable instead of ICollection for the properties Keys and Values. All this would have been so much easier !
I've seen posts here on how to make a dictionary that has multiple values per key, like one of the solutions presented in this link:
Multi Value Dictionary
it seems that I have to use a List<> as the value for the keys, so that a key can store multiple values.
the solution in the link is fine if you want to add values. But my problem now is how to remove specific values from a single key.
I have this code for adding values to a dictionary:
private Dictionary<TKey, List<TValue>> mEventDict;
// this is for initializing the dictionary
public void Subscribe(eVtEvtId inEvent, VtEvtDelegate inCallbackMethod)
{
if (mEventDict.ContainsKey(inEvent))
{
mEventDict[inEvent].Add(inCallbackMethod);
}
else
{
mEventDict.Add(inEvent, new List<TValue>() { v });
}
}
// this is for adding values to the dictionary.
// if the "key" (inEvent) is not yet present in the dictionary,
// the key will be added first before the value
my problem now is removing a specific value from a key. I have this code:
public void Unsubscribe(eVtEvtId inEvent, VtEvtDelegate inCallbackMethod)
{
try
{
mEventDict[inEvent].Remove(inCallbackMethod);
}
catch (ArgumentNullException)
{
MessageBox.Show("The event is not yet present in the dictionary");
}
}
basically, what I did is just replace the Add() with Remove() . Will this work?
Also, if you have any problems or questions with the code (initialization, etc.), feel free to ask.
Thanks for the advice.
TylerOhlsen's answer is a step in the right direction, but it has 6 key lookups (calls to Remove, ContainsKey, and the indexer). This can be reduced to three by using TryGetValue:
private Dictionary<TKey, List<TValue>> mEventDict;
public void Subscribe(TKey inEvent, TValue inCallbackMethod)
{
List<TValue> list;
if (mEventDict.TryGetValue(inEvent, out list))
list.Add(inCallbackMethod);
else
mEventDict.Add(inEvent, new List<TValue> { inCallbackMethod });
}
public bool Unsubscribe(TKey inEvent, TValue inCallbackMethod)
{
List<TValue> list;
if (!mEventDict.TryGetValue(inEvent, out list))
return false;
bool removed = list.Remove(inCallbackMethod);
if (list.Count == 0)
mEventDict.Remove(inEvent);
return removed;
}
If you don't care about removing empty lists:
public bool Unsubscribe(TKey inEvent, TValue inCallbackMethod)
{
List<TValue> list;
if (!mEventDict.TryGetValue(inEvent, out list))
return false;
return list.Remove(inCallbackMethod);
}
If you don't need to report whether the item was in the list (and therefore removed from it), change the return type to void, and (in the first version) get rid of the removed variable.
Will it work? Not exactly the way you intended...
Your method parameters will need to be of the generic types.
List(T).Remove does not throw an ArgumentNullException.
You might want to clean up your dictionary if your list becomes empty.
The caller might not care if the callback was ever subscribed when they unsubscribe, but you have that information so you might as well return it. This information could be helpful for troubleshooting/logging purposes.
This is what I would recommend...
private Dictionary<TKey, List<TValue>> mEventDict;
public void Subscribe(TKey inEvent, TValue inCallbackMethod)
{
if (!mEventDict.ContainsKey(inEvent))
mEventDict.Add(inEvent, new List<TValue>());
mEventDict[inEvent].Add(inCallbackMethod);
}
public bool Unsubscribe(TKey inEvent, TValue inCallbackMethod)
{
if (!mEventDict.ContainsKey(inEvent))
return false;
bool removed = mEventDict[inEvent].Remove(inCallbackMethod);
if (mEventDict[inEvent].Count == 0)
mEventDict.Remove(inEvent);
return removed;
}
NOTE: I have not tested this code, so just try it out. Also, this code is not thread safe.
#phoog - so I want to keep the Unsubscribe method as void . After modifying your code, this is what I came up with...
public void Unsubscribe(TKey inEvent, TValue inCallbackMethod)
{
List<TValue> list;
bool mRemoved = false.
if (mEventDict.TryGetValue(inEvent, out list))
{
list.Remove(inCallbackMethod);
mRemoved = true;
}
}
is the listRemoved variable necessary? But then again, I think nothing will happen if the inCallbackMethod cannot be found in the list.
Is there anything built into the core C# libraries that can give me an immutable Dictionary?
Something along the lines of Java's:
Collections.unmodifiableMap(myMap);
And just to clarify, I am not looking to stop the keys / values themselves from being changed, just the structure of the Dictionary. I want something that fails fast and loud if any of IDictionary's mutator methods are called (Add, Remove, Clear).
No, but a wrapper is rather trivial:
public class ReadOnlyDictionary<TKey, TValue> : IDictionary<TKey, TValue>
{
IDictionary<TKey, TValue> _dict;
public ReadOnlyDictionary(IDictionary<TKey, TValue> backingDict)
{
_dict = backingDict;
}
public void Add(TKey key, TValue value)
{
throw new InvalidOperationException();
}
public bool ContainsKey(TKey key)
{
return _dict.ContainsKey(key);
}
public ICollection<TKey> Keys
{
get { return _dict.Keys; }
}
public bool Remove(TKey key)
{
throw new InvalidOperationException();
}
public bool TryGetValue(TKey key, out TValue value)
{
return _dict.TryGetValue(key, out value);
}
public ICollection<TValue> Values
{
get { return _dict.Values; }
}
public TValue this[TKey key]
{
get { return _dict[key]; }
set { throw new InvalidOperationException(); }
}
public void Add(KeyValuePair<TKey, TValue> item)
{
throw new InvalidOperationException();
}
public void Clear()
{
throw new InvalidOperationException();
}
public bool Contains(KeyValuePair<TKey, TValue> item)
{
return _dict.Contains(item);
}
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
{
_dict.CopyTo(array, arrayIndex);
}
public int Count
{
get { return _dict.Count; }
}
public bool IsReadOnly
{
get { return true; }
}
public bool Remove(KeyValuePair<TKey, TValue> item)
{
throw new InvalidOperationException();
}
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
return _dict.GetEnumerator();
}
System.Collections.IEnumerator
System.Collections.IEnumerable.GetEnumerator()
{
return ((System.Collections.IEnumerable)_dict).GetEnumerator();
}
}
Obviously, you can change the this[] setter above if you want to allow modifying values.
As far as I know, there is not. But maybe you can copy some code (and learn a lot) from these articles:
Immutability in C# Part One: Kinds of Immutability
Immutability in C# Part Two: A Simple Immutable Stack
Immutability in C# Part Three: A Covariant Immutable Stack
Immutability in C# Part Four: An Immutable Queue
Immutability in C# Part Five: LOLZ
Immutability in C# Part Six: A Simple Binary Tree
Immutability in C# Part Seven: More on Binary Trees
Immutability in C# Part Eight: Even More On Binary Trees
Immutability in C# Part Nine: Academic? Plus my AVL tree implementation
Immutability in C# Part 10: A double-ended queue
Immutability in C# Part Eleven: A working double-ended queue
With the release of .NET 4.5, there is a new ReadOnlyDictionary class. You simply pass an IDictionary to the constructor to create the immutable dictionary.
Here is a helpful extension method which can be used to simplify creating the readonly dictionary.
I know this is a very old question, but I somehow found it in 2020 so I suppose it may be worth noting that there is a way to create immutable dictionary now:
https://learn.microsoft.com/en-us/dotnet/api/system.collections.immutable.immutabledictionary.toimmutabledictionary?view=netcore-3.1
Usage:
using System.Collections.Immutable;
public MyClass {
private Dictionary<KeyType, ValueType> myDictionary;
public ImmutableDictionary<KeyType, ValueType> GetImmutable()
{
return myDictionary.ToImmutableDictionary();
}
}
Adding onto dbkk's answer, I wanted to be able to use an object initializer when first creating my ReadOnlyDictionary. I made the following modifications:
private readonly int _finalCount;
/// <summary>
/// Takes a count of how many key-value pairs should be allowed.
/// Dictionary can be modified to add up to that many pairs, but no
/// pair can be modified or removed after it is added. Intended to be
/// used with an object initializer.
/// </summary>
/// <param name="count"></param>
public ReadOnlyDictionary(int count)
{
_dict = new SortedDictionary<TKey, TValue>();
_finalCount = count;
}
/// <summary>
/// To allow object initializers, this will allow the dictionary to be
/// added onto up to a certain number, specifically the count set in
/// one of the constructors.
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
public void Add(TKey key, TValue value)
{
if (_dict.Keys.Count < _finalCount)
{
_dict.Add(key, value);
}
else
{
throw new InvalidOperationException(
"Cannot add pair <" + key + ", " + value + "> because " +
"maximum final count " + _finalCount + " has been reached"
);
}
}
Now I can use the class like so:
ReadOnlyDictionary<string, string> Fields =
new ReadOnlyDictionary<string, string>(2)
{
{"hey", "now"},
{"you", "there"}
};
The open-source PowerCollections library includes a read-only dictionary wrapper (as well as read-only wrappers for pretty much everything else), accessible via a static ReadOnly() method on the Algorithms class.
I don't think so. There is a way to create a read-only List and read only Collection, but I don't think there's a built in read only Dictionary. System.ServiceModel has a ReadOnlyDictinoary implementation, but its internal. Probably wouldn't be too hard to copy it though, using Reflector, or to simply create your own from scratch. It basically wraps an Dictionary and throws when a mutator is called.
One workaround might be, throw a new list of KeyValuePair from the Dictionary to keep the original unmodified.
var dict = new Dictionary<string, string>();
dict.Add("Hello", "World");
dict.Add("The", "Quick");
dict.Add("Brown", "Fox");
var dictCopy = dict.Select(
item => new KeyValuePair<string, string>(item.Key, item.Value));
// returns dictCopy;
This way the original dictionary won't get modified.
"Out of the box" there is not a way to do this. You can create one by deriving your own Dictionary class and implementing the restrictions you need.
I've found an implementation of an Inmutable (not READONLY) implementation of a AVLTree for C# here.
An AVL tree has logarithmic (not constant) cost on each operation, but stills fast.
http://csharpfeeds.com/post/7512/Immutability_in_Csharp_Part_Nine_Academic_Plus_my_AVL_tree_implementation.aspx
You could try something like this:
private readonly Dictionary<string, string> _someDictionary;
public IEnumerable<KeyValuePair<string, string>> SomeDictionary
{
get { return _someDictionary; }
}
This would remove the mutability problem in favour of having your caller have to either convert it to their own dictionary:
foo.SomeDictionary.ToDictionary(kvp => kvp.Key);
... or use a comparison operation on the key rather than an index lookup, e.g.:
foo.SomeDictionary.First(kvp => kvp.Key == "SomeKey");
In general it is a much better idea to not pass around any dictionaries in the first place (if you don't HAVE to).
Instead - create a domain-object with an interface that doesn't offer any methods modifying the dictionary (that it wraps). Instead offering required LookUp-method that retrieves element from the dictionary by key (bonus is it makes it easier to use than a dictionary as well).
public interface IMyDomainObjectDictionary
{
IMyDomainObject GetMyDomainObject(string key);
}
internal class MyDomainObjectDictionary : IMyDomainObjectDictionary
{
public IDictionary<string, IMyDomainObject> _myDictionary { get; set; }
public IMyDomainObject GetMyDomainObject(string key) {.._myDictionary .TryGetValue..etc...};
}
Since Linq, there is a generic interface ILookup.
Read more in MSDN.
Therefore, To simply get immutable dictionary you may call:
using System.Linq;
// (...)
var dictionary = new Dictionary<string, object>();
// (...)
var read_only = dictionary.ToLookup(kv => kv.Key, kv => kv.Value);
There's also another alternative as I have described at:
http://www.softwarerockstar.com/2010/10/readonlydictionary-tkey-tvalue/
Essentially it's a subclass of ReadOnlyCollection>, which gets the work done in a more elegant manner. Elegant in the sense that it has compile-time support for making the Dictionary read-only rather than throwing exceptions from methods that modify the items within it.