C# IDictionary.Keys and IDictionary.Values: what is the most optimal implementation? - c#

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 !

Related

ILookup with empty collections

Is there something inherently wrong with replacing
IDictionary<int, IEnumerable<string>>
with
ILookup<int, string>
I much prefer ILookup over IDictionary because of its more 'honest' interface and immutability.
However, I discovered that ILookup is unable to hold empty collections, so keys containing empty collections are simply do not exist in it. This is problem, because I also would like ILookup to convey information about all possible keys (even though some of them might be empty), so I can go like this:
var statistics = from grouping in myLookup
select new {grouping.Key, grouping.Count()};
which works with dictionary of enumerables, but unfortunately does not work with ILookup. It is just impossible to have entries where grouping.Count()==0, as with IDictionary.
As John Skeet states,
There’s one other important difference between a lookup and a dictionary: if you ask a lookup for the sequence corresponding to a key which it doesn’t know about, it will return an empty sequence, rather than throwing an exception. (A key which the lookup does know about will never yield an empty sequence.)
Now, what is wrong if ILookup allowed empty groupings? In order to have the best of both worlds I am about to add Filter() extension method for ILookup that does just this, but need to resolve a problem that Linq does not allow to create empty IGroupings (so I have to implement my own class), but I feel that maybe I am doing something against design principles of Linq.
Example
Two options:
1) you could create a nice, straightforward singleton-esque EmptyLookup class as follows:
var empty = EmptyLookup<int, string>.Instance;
// ...
public static class EmptyLookup<TKey, TElement>
{
private static readonly ILookup<TKey, TElement> _instance
= Enumerable.Empty<TElement>().ToLookup(x => default(TKey));
public static ILookup<TKey, TElement> Instance
{
get { return _instance; }
}
}
2) You can create a singleton class for empty lookups.
public sealed class EmptyLookup<T, K> : ILookup<T, K>
{
private static readonly EmptyLookup<T, K> _instance
= new EmptyLookup<T, K>();
public static EmptyLookup<T, K> Instance
{
get { return _instance; }
}
private EmptyLookup() { }
public bool Contains(T key)
{
return false;
}
public int Count
{
get { return 0; }
}
public IEnumerable<K> this[T key]
{
get { return Enumerable.Empty<K>(); }
}
public IEnumerator<IGrouping<T, K>> GetEnumerator()
{
yield break;
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
yield break;
}
}
then you can write code like this:
var x = EmptyLookup<int, int>.Instance;
/*The benefit of creating a new class is that you can use the "is" operator and check for type equality:*/
if (x is EmptyLookup<,>) {
// ....
}
There is no wrong in keeping empty groupings is lookup, it's just that lookup does not support it because of it's nature in Linq.
You have to create an extension method by yourself.

Class design for read-only collection properties

I have an IDictionary<string, MyEnum?> collection that needs to be passed to a class to wrap it in a IReadOnlyDictionary<string, MyEnum> (note MyEnum but not MyEnum?).
I have come up with two designs:
Delay the wrapping to IReadOnlyDictionary<string, MyEnum> until property access:
public class MyClass
{
private readonly IEnumerable<KeyValuePair<string, MyEnum?>> _kvps;
public MyClass(IEnumerable<KeyValuePair<string, MyEnum?>> kvps)
{
_kvps = kvps;
}
public IReadOnlyDictionary<string, MyEnum> Kvps
{
get
{
var filtered = from kvp in _kvps
where kvp.Value.HasValue
select kvp;
return new ReadOnlyDictionary<string, MyEnum>(
filtered.ToDictionary(kvp => kvp.Key, kvp => (MyEnum)kvp.Value);
}
}
}
Eagerly evaluate the collection in constructor
public class MyClass
{
public MyClass(IEnumerable<KeyValuePair<string, MyEnum?>> kvps)
{
Kvps = ToReadOnly(kvps);
}
public IReadOnlyDictionary<string, MyEnum> Kvps { get; }
private static IReadOnlyDictionary<string, MyEnum> ToReadOnly(
IEnumerable<KeyValuePair<string, MyEnum?>> kvps)
{
var filtered = from kvp in kvps
where kvp.Value.HasValue
select kvp;
return new ReadOnlyDictionary<string, MyEnum>(
filtered.ToDictionary(kvp => kvp.Key, kvp => (MyEnum)kvp.Value);
}
}
The constructor design section of the Framework Design Guidelines suggests that minimal work should be done in constructors so I am opting for the first approach. However, that means every call to MyClass.Kvps will trigger a copy of _kvps which is not ideal.
I would like to know which is a better approach (or are there other ways) in terms of:
Memory efficiency (ideally only one copy of the collection is stored in MyClass)
Performance (property access should be fast and should not trigger a copy of the KeyValuePairs)
Out of the two requirements - don't copy the key value pairs and don't store two copies - you'll have to break one.
What causes us to look at this and think that there must be a solution is that we see TValue and TValue? and our minds want to see them as being of the same type. But they are not the same type.
It becomes clearer if you imagine that instead of TValue and TValue? that these are two different types, like an int and a string, and we want to project a collection of one to a collection of the other while filtering. For example,
List<string> GetStringsFromNonNegativeInts(List<int> ints)
{
return ints.Where(i=>i>-1).Select(i=>i.ToString()).ToList();
}
That's exactly the same scenario as trying to filter a set of TValue? to a set of TValue, even without the dictionary. It's just harder to see. TValue and TValue? code-blind us.
There are only two ways to do this. One is to copy each time, and the other is to keep two lists in synchronization.
EDIT: If you want the latest source values, best way is to implement your own class that implements IReadOnlyDictionary. Initialize this with a private field of ReadOnlyDictionary<string, MyEnum?>. Each call will do the lookup, and if the key exists AND HasValue, return the value.
Note that this implementation depends on the reference to the original values being passed in as an IReadOnlyDictionary to avoid having to copy values over.
public class MyReadOnlyDictionary<TKey, TValue> : IReadOnlyDictionary<TKey, TValue> where TValue : struct
{
// other methods to implement here...
public MyReadOnlyDictionary(IReadOnlyDictionary<TKey, TValue?> kvps)
{
_kvps = kvps;
}
private IReadOnlyDictionary<TKey, TValue?> _kvps;
new public TValue this[TKey key]
{
get
{
TValue? val = _kvps[key];
if (val.HasValue)
return val.Value;
throw new KeyNotFoundException();
}
}
}

What is the simplest way to rename Key and Value properties in Dictionary<> subclasses

I have a complex data container with multiple levels of nested Dictionaries.
But having Key and Value properties make it non-intuitive and hard to use.
Please suggest the simplest way to rename Key and Value properties in Dictionary<,> subclasses.
Update:
Patryk Ćwiek: If you implement IDictionary<TKey, TValue>, you also can't rename properties, because they're part of the contract.
You're right. My question was not correct. Usage of KeyValuePair in IDictionary restrict the pair properties to Key and Value. So if we want non Key/Value pair we had to implement IDictionary with custom KeyValuePair struct. Or may be there is some other tricky way?
PS. Maybe someone suggest an IDictionary code generation template?
Make your own interface with the property name(s) you want. Then, have your concrete class implement your custom interface.
To keep your code DRY, create a private Dictionary that you delegate all of your work to. You can even have your custom interface be Enumerable (or anything else that IDictionary implements) by delegating the required methods to your private variable.
Here is an example. You would just need change your code from using IDictionary to IComplexDataContainer.
interface IComplexDataContainer<TKey, TValue>
: IEnumerable<KeyValuePair<TKey,TValue>>
{
TValue this[TKey index] { get; set; }
}
class MyComplexDataContainer<TKey, TValue>
: IComplexDataContainer<TKey, TValue>
{
IDictionary<TKey, TValue> hiddenHelper { get; set; }
public MyComplexDataContainer()
{
hiddenHelper = new Dictionary<TKey, TValue>();
}
// delegate all of the work to the hidden dictionary
public TValue this[TKey index]
{
get
{
return hiddenHelper[index];
}
set
{
hiddenHelper[index] = value;
}
}
// Just delegate the IEnumerable interface to your hidden dictionary
// or any other interface you want your class to implement
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
return hiddenHelper.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Then you would just use like this:
IComplexDataContainer<string, int> myData = new MyComplexDataContainer<string,int>();
myData["tom"] = 18;
myData["dick"] = 22;
myData["harry"] = myData["tom"];

remove specific values from multi value dictionary

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.

Does C# have a way of giving me an immutable Dictionary?

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.

Categories