Skip to content

Instantly share code, notes, and snippets.

@MrZoidberg
Created November 27, 2012 22:01
Show Gist options
  • Save MrZoidberg/4157432 to your computer and use it in GitHub Desktop.
Save MrZoidberg/4157432 to your computer and use it in GitHub Desktop.
Dictionary that smartly track changes of the values
class Program
{
static void Main(string[] args)
{
var dict = new SmartTrackingDictionary<string, object>();
dict["int"] = 1;
dict["int"] = 2;
Console.WriteLine("key 'int' {0}", dict.IsChanged("int") ? "has changed" : "hasn't changed");
dict["str"] = "string1";
dict["str"] = "string2";
Console.WriteLine("key 'str' {0}", dict.IsChanged("str") ? "has changed" : "hasn't changed");
}
}
public class SmartTrackingDictionary<TKey, TValue> : IDictionary<TKey, TValue>
{
private const string CountString = "Count";
private const string IndexerName = "Item[]";
private const string KeysName = "Keys";
private const string ValuesName = "Values";
private IDictionary<TKey, TValue> _Dictionary;
protected IDictionary<TKey, TValue> Dictionary
{
get { return _Dictionary; }
}
private Dictionary<TKey, bool> _changesDict;
#region Constructors
public SmartTrackingDictionary()
{
_Dictionary = new Dictionary<TKey, TValue>();
_changesDict = new Dictionary<TKey, bool>();
}
public SmartTrackingDictionary(IDictionary<TKey, TValue> dictionary)
{
_Dictionary = new Dictionary<TKey, TValue>(dictionary);
_changesDict = new Dictionary<TKey, bool>();
}
public SmartTrackingDictionary(IEqualityComparer<TKey> comparer)
{
_Dictionary = new Dictionary<TKey, TValue>(comparer);
_changesDict = new Dictionary<TKey, bool>();
}
public SmartTrackingDictionary(int capacity)
{
_Dictionary = new Dictionary<TKey, TValue>(capacity);
_changesDict = new Dictionary<TKey, bool>();
}
public SmartTrackingDictionary(IDictionary<TKey, TValue> dictionary, IEqualityComparer<TKey> comparer)
{
_Dictionary = new Dictionary<TKey, TValue>(dictionary, comparer);
_changesDict = new Dictionary<TKey, bool>();
}
public SmartTrackingDictionary(int capacity, IEqualityComparer<TKey> comparer)
{
_Dictionary = new Dictionary<TKey, TValue>(capacity, comparer);
_changesDict = new Dictionary<TKey, bool>();
}
#endregion
#region IDictionary<TKey,TValue> Members
public void Add(TKey key, TValue value)
{
Insert(key, value, true);
}
public bool ContainsKey(TKey key)
{
return Dictionary.ContainsKey(key);
}
public ICollection<TKey> Keys
{
get { return Dictionary.Keys; }
}
public bool Remove(TKey key)
{
if (key == null) throw new ArgumentNullException("key");
TValue value;
Dictionary.TryGetValue(key, out value);
var removed = Dictionary.Remove(key);
if (removed)
{
_changesDict.Remove(key);
}
return removed;
}
public bool TryGetValue(TKey key, out TValue value)
{
return Dictionary.TryGetValue(key, out value);
}
public ICollection<TValue> Values
{
get { return Dictionary.Values; }
}
public TValue this[TKey key]
{
get
{
return Dictionary[key];
}
set
{
Insert(key, value, false);
}
}
#endregion
#region ICollection<KeyValuePair<TKey,TValue>> Members
public void Add(KeyValuePair<TKey, TValue> item)
{
Insert(item.Key, item.Value, true);
}
public void Clear()
{
if (Dictionary.Count > 0)
{
Dictionary.Clear();
_changesDict.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 int Count
{
get { return Dictionary.Count; }
}
public bool IsReadOnly
{
get { return Dictionary.IsReadOnly; }
}
public bool Remove(KeyValuePair<TKey, TValue> item)
{
return Remove(item.Key);
}
#endregion
#region IEnumerable<KeyValuePair<TKey,TValue>> Members
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
return Dictionary.GetEnumerator();
}
#endregion
#region IEnumerable Members
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable)Dictionary).GetEnumerator();
}
#endregion
public void AddRange(IDictionary<TKey, TValue> items)
{
if (items == null) throw new ArgumentNullException("items");
if (items.Count > 0)
{
if (items.Keys.Any((k) => Dictionary.ContainsKey(k)))
throw new ArgumentException("An item with the same key has already been added.");
else
foreach (var item in items)
{
Dictionary.Add(item);
_changesDict.Add(item.Key, false);
}
}
}
private void Insert(TKey key, TValue value, bool add)
{
if (key == null) throw new ArgumentNullException("key");
TValue item;
if (Dictionary.TryGetValue(key, out item))
{
if (add) throw new ArgumentException("An item with the same key has already been added.");
if (IsValuesEqual(item, value)) return;
Dictionary[key] = value;
_changesDict[key] = true;
}
else
{
Dictionary[key] = value;
_changesDict[key] = false;
}
}
private bool IsValuesEqual(TValue value1, TValue value2)
{
if (value1 == null && value2 == null)
return true;
if (ReferenceEquals(null, value2)) return false;
if (ReferenceEquals(null, value2)) return false;
Type valueType = value1.GetType();
if (valueType != value2.GetType())
return false;
if (valueType.IsValueType)
{
return value1.Equals(value2);
}
//will not work for complex objects
//if (ReferenceEquals(value1, value2)) return true;
var specificEquals = valueType.GetMethod("Equals", new Type[] { valueType });
if (specificEquals != null &&
specificEquals.ReturnType == typeof(bool))
{
return (bool)specificEquals.Invoke(value1, new object[] { value2 });
}
return value1.Equals(value2);
}
public bool IsChanged(TKey key)
{
return _changesDict[key];
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment