Skip to content

Instantly share code, notes, and snippets.

@Pzixel
Created June 29, 2016 12:47
Show Gist options
  • Save Pzixel/01cce08812dda273a0d41b5bdaa3a7e0 to your computer and use it in GitHub Desktop.
Save Pzixel/01cce08812dda273a0d41b5bdaa3a7e0 to your computer and use it in GitHub Desktop.
public class NullableDictionary<TKey, TValue> : IDictionary<TKey?, TValue> where TKey : struct
{
private bool _hasNull;
private TValue _nullKeyValue;
private readonly Dictionary<TKey, TValue> _dictionary;
public NullableDictionary(): this(0, null) { }
public NullableDictionary(int capacity): this(capacity, null) { }
public NullableDictionary(IEqualityComparer<TKey> comparer): this(0, comparer) { }
public NullableDictionary(int capacity, IEqualityComparer<TKey> comparer)
{
_dictionary = new Dictionary<TKey, TValue>(capacity, comparer);
}
public NullableDictionary(IDictionary<TKey, TValue> dictionary): this(dictionary, null) { }
public NullableDictionary(IDictionary<TKey, TValue> dictionary, IEqualityComparer<TKey> comparer) :
this(dictionary?.Count ?? 0, comparer)
{
if (dictionary == null)
{
throw new ArgumentNullException(nameof(dictionary));
}
foreach (var pair in dictionary)
{
Add(pair.Key, pair.Value);
}
}
public IEnumerator<KeyValuePair<TKey?, TValue>> GetEnumerator()
{
if (_hasNull)
yield return new KeyValuePair<TKey?, TValue>(null, _nullKeyValue);
foreach (var pair in _dictionary)
{
yield return new KeyValuePair<TKey?, TValue>(pair.Key, pair.Value);
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable) _dictionary).GetEnumerator();
}
public void Add(KeyValuePair<TKey?, TValue> item)
{
Add(item.Key, item.Value);
}
public void Clear()
{
_hasNull = false;
_nullKeyValue = default(TValue);
_dictionary.Clear();
}
public bool Contains(KeyValuePair<TKey?, TValue> item)
{
if (!item.Key.HasValue)
{
return _hasNull;
}
return _dictionary.Contains(new KeyValuePair<TKey, TValue>(item.Key.GetValueOrDefault(), item.Value));
}
public void CopyTo(KeyValuePair<TKey?, TValue>[] array, int arrayIndex)
{
foreach (var pair in this)
{
array[arrayIndex++] = pair;
}
}
public bool Remove(KeyValuePair<TKey?, TValue> item)
{
if (!item.Key.HasValue)
{
var hadNull = _hasNull;
_hasNull = false;
return hadNull;
}
return _dictionary.Remove(item.Key.GetValueOrDefault());
}
public int Count => _hasNull ? _dictionary.Count + 1 : _dictionary.Count;
public bool IsReadOnly => false;
public bool ContainsKey(TKey? key)
{
if (!key.HasValue)
{
return _hasNull;
}
return _dictionary.ContainsKey(key.GetValueOrDefault());
}
public void Add(TKey? key, TValue value)
{
if (!key.HasValue)
{
if (_hasNull)
{
throw new ArgumentException("Dictionary already has a null key value pair");
}
_hasNull = true;
_nullKeyValue = value;
}
else
{
_dictionary.Add(key.GetValueOrDefault(), value);
}
}
public bool Remove(TKey? key)
{
if (!key.HasValue)
{
bool hadNull = _hasNull;
_hasNull = false;
return hadNull;
}
return _dictionary.Remove(key.GetValueOrDefault());
}
public bool TryGetValue(TKey? key, out TValue value)
{
if (!key.HasValue)
{
value = _nullKeyValue;
return _hasNull;
}
return _dictionary.TryGetValue(key.GetValueOrDefault(), out value);
}
public TValue this[TKey? key]
{
get
{
if (!key.HasValue)
{
if (_hasNull)
{
return _nullKeyValue;
}
throw new KeyNotFoundException();
}
return _dictionary[key.GetValueOrDefault()];
}
set { Add(key, value); }
}
public ICollection<TKey?> Keys => this.Select(x => x.Key).ToList();
public ICollection<TValue> Values => this.Select(x => x.Value).ToList();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment