Class design for read-only collection properties - c#

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();
}
}
}

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.

Is it possible to create a method that returns one of two possible types?

I have 2 data structures: Dictionary<string, string> and Multimap<string, string>.
Multimap is really just a Dictionary under the hood. I took must of the code from this question. Here's the class definition:
public class Multimap<TKey, TValue> : Dictionary<TKey, HashSet<TValue>>
{ ... }
Both data structures have a .Add(TKey key, TValue value) method.
I have a class that is responsible for populating these maps from certain files. I currently have the following two methods:
public Dictionary<string, string> PopulateDictionary(...)
{
Dictionary<string, string> returnDictionary = new Dictionary<string, string>();
...
foreach (...)
{
...
returnDictionary.Add(key, value);
}
return returnDictionary;
}
public Multimap<string, string> PopulateMultimap(...)
{
Multimap<string, string> returnMultimap = new Multimap<string, string>();
...
foreach (...)
{
...
returnMultimap.Add(key, value);
}
return returnMultimap;
}
As you can see, they're exactly the same, both around 25 lines long, and the only difference is their return type. What I am looking to do is condense this into one method.
My first attempt was to have the method
public Dictionary<string, object> PopulateGenericDictionary(...)
{ ... }
Where object was either string or HashSet<string>. But I didn't have much luck casting from Dictionary<string, object> to Multimap<string, string>.
Extracting the logic out of the methods is an option, but it's not great. Because of the foreach loops, there's always going to be some logic inside the two methods. You do end up with methods that are twice as small, but there's still two identical methods, which doesn't truly solve the problem.
This would be my ideal method structure:
public Dictionary<string, string> PopulateDictionary(...)
{
return MethodThatDoesAllTheLogic(...);
}
public Multimap<string, string> PopulateMultimap(...)
{
return MethodThatDoesAllTheLogic(...);
}
public ??? MethodThatDoesAllTheLogic(...)
{ ... }
I've been fiddling around with casting and generics, but I just can't get it to work. Any ideas?
Edit
I have used millimoose's solution. Here's my code now:
public Dictionary<string, string> GenerateDictionary(...)
{
Dictionary<string, string> returnMap = new Dictionary<string, string>();
PopulateDictionary(returnMap.Add, ...);
return returnMap;
}
public Multimap<string, string> GenerateMultimap(...)
{
Multimap<string, string> returnMap = new Multimap<string, string>();
PopulateDictionary(returnMap.Add, ...);
return returnMap;
}
private static void PopulateGenericDictionary(Action<string, string> addFunc, ...)
{
...
foreach (...)
{
addFunc(key, value);
}
}
Much cleaner!
To work around the lack of a common interface, you can invent one ad-hoc using a bunch of delegate type parameters:
void MethodThatDoesAllTheLogic(Action<string, string> addFunc)
{
// ...
addFunc(key, value);
// ...
}
public Dictionary<...> PopulateDictionary()
{
// ...
MethodThatDoesAllTheLogic(result.Add);
}
(Adding more parameters as necessary.)
I would avoid having the helper method create the actual collection at all; have it just populate an existing collection. That can be done much more effectively, since the Add method has the same signature in both cases. We can just use a delegate to accept the Add method:
public static void PopulateMapping<TKey, TValue>(Action<TKey, TValue> addMethod,
IEnumerable<TKey> data) //include other parameters needed to populate the data
{
foreach (var key in data)
{
addMethod(key, default(TValue));
}
}
Then it would be used like this:
public static Dictionary<string, string> PopulateDictionary()
{
Dictionary<string, string> output = new Dictionary<string, string>();
PopulateMapping<string, string>(output.Add, new string[] { "a" });
return output;
}
If you are only looking for an Add method, then both objects should share IDictionary. However, that Add method only uses objects. That is probably the closest that you can get without having to use generics in the method...but again you lose the benefits of generics at that point.
See if this approach will be useful:
The key is to make abstraction on creation of the object (Dictionary or Multimap) and aquiring the values - the two differences in the populating method.
public Dictionary<string, TValue> Populate<TValue>( Dictionary<string, TValue> returnDict, Func<SomeType, TValue> valueProvider)
{
string key = null;
...
foreach (...)
{
...
returnDict.Add(key, valueProvider(value));
}
return returnDict;
}
The example invocation is can be:
public void Test()
{
Populate(new Multimap<string, HashSet<string>>(), (t) => new HashSet<HashSet<string>>());
}
I'm not sure if the valueProvider delegate will be suited to your problem. Try to give more information about it.
If your inner logic is truly identical except for what type TValue is - and I mean word-for-word identical - then you could do something like:
IDictionary<string, TValue> MethodThatDoesAllTheLogic<TValue>(whatever)
{
// word for word-identical logic
}
I made the method take TValue as its only type parameter because that's the only difference (in the example you showed): both methods have string as the first type parameter.
ETA: This assumes that MultiMap implements IDictionary<K,V>. Since you said that it inherited from Dictionary<K,V> I assumed that it did.
in C# with generics you can require them to extend or implement a specific class in our case Dictionary, the following is how you might achieve that.
public T Populate<T>(string val) where T : Dictionary<string, string>, new()
{
T returnDict = new T();
returnDict.Add("key", "val");
return returnDict;
}

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

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 !

Need an IDictionary<TKey,TValue> implementation that will allow a null key

Basically, I want something like this:
Dictionary<object, string> dict = new Dictionary<object, string>();
dict.Add(null, "Nothing");
dict.Add(1, "One");
Are there any built into the base class library that allow this? The preceding code will throw an exception at runtime when adding the null key.
You could avoid using null and create a special singleton value class that does the same thing. For example:
public sealed class Nothing
{
public static readonly Nothing Value = new Nothing();
private Nothing() {}
}
Dictionary<object, string> dict = new Dictionary<object, string>();
dict.add(Nothing.Value, "Nothing");
dict.add(1, "One");
This approach will fail to work if you intend to make your collection more strongly typed - let's say for example you want the key to be a string. Since string is sealed you can't inherit from it to create a "special value" substitute for null. Your alternatives become a bit more complicated. You could:
Create some special constant value to represent the "empty" / "null" case. Kind of hacky and definitely a path to confusion. This can be a viable approach if the dictionary is completely private to some implementation class and you can write some Encode/Decode utility methods to avoid spreading the knowledge of how you translate keys all over the place.
Create your own implementation of IDictionary that internally delegates to a Dictionary<> instance - except for the case of null. This violates the documented expectations for the IDictionary<> interface which does say that null keys should throw an exception. But you may be able to get away with it if it's the only way to solve your real problem. This only works if you own and create the dictionary instance.
Find a way to solve your problem without storing a "null" key in the dictionary. For example, consider not populating the null key in the dictionary and having some special case logic to deal with it. Keys have to be hashable and comparable to work with the underlying implementation, which is why null is prohibited normally.
As an aside, does your dictionary key really need the key to be object? This can lead to subtle bugs due to reference equality being used where you may have intended Equals() to be evaluated as the basis for comparison.
How about this?
public class NullableDictionnary<T1, T2> : Dictionary<T1, T2>
{
T2 null_value;
public T2 this[T1 key]
{
get
{
if (key == null)
{ return null_value; }
return base[key];
}
set
{
if (key == null)
{ null_value = value; }
else
{ base[key] = value; }
}
}
}
NameValueCollection can take a null key but it does not implement IDictionary. It would however be pretty easy to derive from DictionaryBase and provide Add/Remove/Indexers etc that simply replace null with something built in like:
class MyDictionary : DictionaryBase {
private readonly object nullKey = new object();
void Add(object key, string value) {
if ( key == null ) { key = nullKey; }
.. call base methods
}
}
You can simply use ValueTuple as a wrapper for key, for example:
Dictionary<ValueTuple<string?>, string>
No need for a different implementation of Dictionary.
Take a look at my answer here:
https://stackoverflow.com/a/22261282/212272
You will also be able to keep your dictionary strongly typed:
var dict = new Dictionary<NullObject<int?>, string>();
dict[1] = "one int";
dict[null] = "null int";
Assert.AreEqual("one int", dict[1]);
Assert.AreEqual("null int", dict[null]);
If key is enum, you can use not existing value instead of null like (YourEnum)(-1)
Does the key literally need to be NULL? The key in the collection works out to be an index. It doesn't make a lot of sense to me to have NULL for an index in a collection.
Maybe create a new class
public class ObjectEntry
{
public object objRef;
public string desc;
public ObjectEntry(object objectReference)
{
objRef = objectReference;
if (objRef = null) {desc = "Nothing";}
else {desc = objRef.Description;} //or whatever info you can get from a proper objRef value
}
}
newObj = new ObjectEntry(null);
dict.add(newObj, newObj.desc);
A slight variation on jestro's answer to make for a cleaner(to me) solution that makes it more explicit what you are trying to do. Obviously this could be extended as needed. But you get the picture, just make a wrapper.
public class NullDictionary<TKey, TValue> : Dictionary<TKey, TValue>
{
private TValue _default;
public new TValue this[TKey key]
{
get {
if(key == null)
{
return _default;
}
return _decorated[key];
}
}
private Dictionary<TKey, TValue> _decorated;
public NullDictionary( Dictionary<TKey,TValue> decorate, TValue defaultValue = default)
{
_decorated = decorate;
_default = defaultValue;
}
}

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