I used encapsulation to create an IDictionary with behavior very similar to an STL map, for those of you who are familiar with c++. For those who aren't:
- indexer get {} in SafeDictionary below returns the default value if a key is not present, and adds that key to the dictionary with a default value. This is often the desired behavior, as you're looking up items that will appear eventually or have a good chance of appearing.
- method Add(TK key, TV val) behaves as an AddOrUpdate method, replacing the value present if it exists instead of throwing. I don't see why m$ doesn't have an AddOrUpdate method and thinks throwing errors in very common scenarios is a good idea.
TL/DR - SafeDictionary is written so as to never throw exceptions under any circumstances, other than perverse scenarios, such as the computer being out of memory (or on fire). It does this by replacing Add with AddOrUpdate behavior and returning default instead of throwing NotFoundException from the indexer.
Here's the code:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
public class SafeDictionary<TK, TD>: IDictionary<TK, TD> {
Dictionary<TK, TD> _underlying = new Dictionary<TK, TD>();
public ICollection<TK> Keys => _underlying.Keys;
public ICollection<TD> Values => _underlying.Values;
public int Count => _underlying.Count;
public bool IsReadOnly => false;
public TD this[TK index] {
get {
TD data;
if (_underlying.TryGetValue(index, out data)) {
return data;
}
_underlying[index] = default(TD);
return default(TD);
}
set {
_underlying[index] = value;
}
}
public void CopyTo(KeyValuePair<TK, TD>[] array, int arrayIndex) {
Array.Copy(_underlying.ToArray(), 0, array, arrayIndex,
Math.Min(array.Length - arrayIndex, _underlying.Count));
}
public void Add(TK key, TD value) {
_underlying[key] = value;
}
public void Add(KeyValuePair<TK, TD> item) {
_underlying[item.Key] = item.Value;
}
public void Clear() {
_underlying.Clear();
}
public bool Contains(KeyValuePair<TK, TD> item) {
return _underlying.Contains(item);
}
public bool ContainsKey(TK key) {
return _underlying.ContainsKey(key);
}
public IEnumerator<KeyValuePair<TK, TD>> GetEnumerator() {
return _underlying.GetEnumerator();
}
public bool Remove(TK key) {
return _underlying.Remove(key);
}
public bool Remove(KeyValuePair<TK, TD> item) {
return _underlying.Remove(item.Key);
}
public bool TryGetValue(TK key, out TD value) {
return _underlying.TryGetValue(key, out value);
}
IEnumerator IEnumerable.GetEnumerator() {
return _underlying.GetEnumerator();
}
}