Skip to content

Instantly share code, notes, and snippets.

@sehe
Created May 25, 2012 19:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sehe/2789882 to your computer and use it in GitHub Desktop.
Save sehe/2789882 to your computer and use it in GitHub Desktop.
DefaultingDictionary<>
using System;
using System.Collections;
using System.Collections.Generic;
namespace SODemo
{
public class DefaultingDictionary<TKey, TValue> : IDictionary<TKey, TValue>
{
public static implicit operator DefaultingDictionary<TKey,TValue>(Dictionary<TKey,TValue> wrappable)
{
return new DefaultingDictionary<TKey, TValue>(wrappable, default(TValue));
}
private readonly IDictionary<TKey, TValue> _dictionary;
private readonly Func<TKey, TValue> _generateDefault;
public DefaultingDictionary(IDictionary<TKey, TValue> dictionary, Func<TKey, TValue> generateGenerateDefault)
{
_dictionary = dictionary;
_generateDefault = generateGenerateDefault;
}
public DefaultingDictionary(IDictionary<TKey, TValue> dictionary, Func<TValue> generateGenerateDefault)
{
_dictionary = dictionary;
_generateDefault = curry => generateGenerateDefault();
}
public DefaultingDictionary(IDictionary<TKey, TValue> dictionary, TValue defaultValue)
{
_dictionary = dictionary;
_generateDefault = curry => defaultValue;
}
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
return _dictionary.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public void Add(KeyValuePair<TKey, TValue> item)
{
_dictionary.Add(item);
}
public void Clear()
{
_dictionary.Clear();
}
public bool Contains(KeyValuePair<TKey, TValue> item)
{
return _dictionary.Contains(item);
}
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
{
_dictionary.CopyTo(array, arrayIndex);
}
public bool Remove(KeyValuePair<TKey, TValue> item)
{
return _dictionary.Remove(item);
}
public int Count
{
get { return _dictionary.Count; }
}
public bool IsReadOnly
{
get { return _dictionary.IsReadOnly; }
}
public bool ContainsKey(TKey key)
{
return _dictionary.ContainsKey(key);
}
public void Add(TKey key, TValue value)
{
_dictionary.Add(key, value);
}
public bool Remove(TKey key)
{
return _dictionary.Remove(key);
}
public bool TryGetValue(TKey key, out TValue value)
{
if (!_dictionary.TryGetValue(key, out value))
value = _generateDefault(key);
return true;
}
public TValue this[TKey key]
{
get
{
if (!_dictionary.ContainsKey(key))
_dictionary.Add(key, _generateDefault(key));
return _dictionary[key];
}
set
{
if (!_dictionary.ContainsKey(key))
_dictionary.Add(key, value);
else
_dictionary[key] = value;
}
}
public ICollection<TKey> Keys
{
get { return _dictionary.Keys; }
}
public ICollection<TValue> Values
{
get
{
return _dictionary.Values;
}
}
public bool ContainsValue(TValue value)
{
// preferred because it could use a custom Comparer:
var instance = _dictionary as Dictionary<TKey, TValue>;
return instance != null
? instance.ContainsValue(value)
: Values.Contains(value);
}
}
public static class DefaultingDictionaryExtensions
{
public static IDictionary<TKey, TValue> AsDefaulting<TKey, TValue>(this IDictionary<TKey, TValue> dictionary)
{ return new DefaultingDictionary<TKey, TValue>(dictionary, default(TValue)); }
public static IDictionary<TKey, TValue> AsDefaultingTo<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TValue defaultValue )
{ return new DefaultingDictionary<TKey, TValue>(dictionary, defaultValue); }
public static IDictionary<TKey, TValue> AsDefaulting<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, Func<TKey, TValue> func)
{ return new DefaultingDictionary<TKey, TValue>(dictionary, func); }
public static IDictionary<TKey, TValue> AsDefaulting<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, Func<TValue> func)
{ return new DefaultingDictionary<TKey, TValue>(dictionary, func); }
}
}
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace SODemo.Tests
{
[TestClass]
public class DefaultingDictionaryTests
{
[TestMethod]
public void DefaultingDictionary()
{
var vanilla = new Dictionary<int, bool>();
Assert.IsFalse(vanilla.ContainsKey(42));
Throws(typeof (KeyNotFoundException), () => Assert.IsFalse(vanilla[42]));
Assert.IsFalse(vanilla.ContainsKey(42));
vanilla[42] = false;
Assert.IsFalse(vanilla[42]);
Assert.IsTrue(vanilla.ContainsKey(42));
vanilla[42] = true;
Assert.IsTrue(vanilla[42]);
Assert.IsTrue(vanilla.ContainsKey(42));
vanilla[42] = false;
Assert.IsFalse(vanilla[42]);
Assert.IsTrue(vanilla.ContainsKey(42));
vanilla.Remove(42);
Assert.IsFalse(vanilla.ContainsKey(42));
///////////////////////////////////////////////////
var defaulting = vanilla.AsDefaulting();
Assert.IsFalse(defaulting.ContainsKey(42));
Assert.IsFalse(defaulting[42]);
Assert.IsTrue(defaulting.ContainsKey(42));
defaulting[42] = false;
Assert.IsFalse(defaulting[42]);
Assert.IsTrue(defaulting.ContainsKey(42));
defaulting[42] = true;
Assert.IsTrue(defaulting[42]);
Assert.IsTrue(defaulting.ContainsKey(42));
defaulting[42] = false;
Assert.IsFalse(defaulting[42]);
Assert.IsTrue(defaulting.ContainsKey(42));
defaulting.Remove(42);
Assert.IsFalse(defaulting.ContainsKey(42));
Assert.IsFalse(vanilla.ContainsKey(42));
Assert.IsFalse(defaulting[42]);
Assert.IsTrue(defaulting.ContainsKey(42));
Assert.IsTrue(vanilla.ContainsKey(42));
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment