As @JanDotNet explains in their [answer](https://codereview.stackexchange.com/a/166379/50704), your `DataTable<TRow, TCol, TCell>` does not handle hash collisions at all. If a two two-item keys happen to have the same hash, your dictionary will overwrite the value for the first with the value for the second in random, hard-to-reproduce situations. Since `Dictionary<TKey, TValue>` is already [designed to handle hash collisions](https://stackoverflow.com/a/2975784), I would recommend that, before implementing your own replacement from scratch, you ask: *is there any way I can use the existing `Dictionary<TKey, TValue>` type with two symmetric keys*? And, in fact, this can be done, because a .Net dictionary can be constructed with a [custom `IEqualityComparer`](https://msdn.microsoft.com/en-us/library/ms132072(v=vs.110).aspx). Given that, your problem now simplifies to: how can I create an equality comparer between pairs of keys that is symmetric? Assuming you have access to the [`Tuple`](https://msdn.microsoft.com/en-us/library/system.tuple(v=vs.110).aspx) or [`ValueTuple`](https://msdn.microsoft.com/en-us/library/system.valuetuple(v=vs.110).aspx) types, you can create the following `IEqualityComparer` and [extension methods](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/extension-methods): public class SymmetricTupleComparer<T1> : IEqualityComparer<Tuple<T1, T1>> { IEqualityComparer<T1> comparer = EqualityComparer<T1>.Default; #region IEqualityComparer<Tuple<T1,T1>> Members public bool Equals(Tuple<T1, T1> x, Tuple<T1, T1> y) { if (object.ReferenceEquals(x, y)) return true; else if (object.ReferenceEquals(x, null) || object.ReferenceEquals(y, null)) return false; if (comparer.Equals(x.Item1, y.Item1) && comparer.Equals(x.Item2, y.Item2)) return true; if (comparer.Equals(x.Item1, y.Item2) && comparer.Equals(x.Item2, y.Item1)) return true; return false; } public int GetHashCode(Tuple<T1, T1> obj) { if (obj == null) return 0; // Here we use the fact that the XOR operator is symmetric return comparer.GetHashCode(obj.Item1) ^ comparer.GetHashCode(obj.Item2); } #endregion } public static partial class DictionaryExtensions { // Extension methods for dictionaries of symmetric pairs. // https://unity3d.com/learn/tutorials/topics/scripting/extension-methods public static void Add<TKey, TValue>(this IDictionary<Tuple<TKey, TKey>, TValue> dictionary, TKey item1, TKey item2, TValue value) { if (dictionary == null) throw new ArgumentNullException(); dictionary.Add(Tuple.Create(item1, item2), value); } public static void Set<TKey, TValue>(this IDictionary<Tuple<TKey, TKey>, TValue> dictionary, TKey item1, TKey item2, TValue value) { if (dictionary == null) throw new ArgumentNullException(); dictionary[Tuple.Create(item1, item2)] = value; } public static bool Remove<TKey, TValue>(this IDictionary<Tuple<TKey, TKey>, TValue> dictionary, TKey item1, TKey item2) { if (dictionary == null) throw new ArgumentNullException(); return dictionary.Remove(Tuple.Create(item1, item2)); } public static bool TryGetValue<TKey, TValue>(this IDictionary<Tuple<TKey, TKey>, TValue> dictionary, TKey item1, TKey item2, out TValue value) { if (dictionary == null) throw new ArgumentNullException(); return dictionary.TryGetValue(Tuple.Create(item1, item2), out value); } } Notice that: - `GetHashCode()` XOR's the hash codes of the items. Since XOR is symmetric, two tuples with flipped items will have the same hash code. - `Equals()` checks whether the items are identical or identical when flipped. And now you can use the comparer and extension methods as follows: var dictionary = new Dictionary<Tuple<int, int>, string>(new SymmetricTupleComparer<int>()); dictionary.Set(1, 0, "hello"); Console.WriteLine(dictionary.Get(0, 1)); Sample [fiddle](https://dotnetfiddle.net/up2NId) with basic tests working. If you don't have access to `Tuple` or `ValueTuple` you can create your own generic symmetric pair quite easily: public struct SymmetricPair<TKey> : IEquatable<SymmetricPair<TKey>> { readonly TKey item1; readonly TKey item2; public SymmetricPair(TKey item1, TKey item2) { this.item1 = item1; this.item2 = item2; } public TKey Item1 { get { return item1; } } public TKey Item2 { get { return item2; } } #region IEquatable<SymmetricPair<TKey>> Members public bool Equals(SymmetricPair<TKey> other) { var comparer = EqualityComparer<TKey>.Default; if (comparer.Equals(Item1, other.Item1) && comparer.Equals(Item2, other.Item2)) return true; if (comparer.Equals(Item2, other.Item1) && comparer.Equals(Item1, other.Item2)) return true; return false; } #endregion public override bool Equals(object obj) { if (!(obj is SymmetricPair<TKey>)) return false; return Equals((SymmetricPair<TKey>)obj); } public override int GetHashCode() { var comparer = EqualityComparer<TKey>.Default; // Note that the XOR operator is symmetric return comparer.GetHashCode(Item1) ^ comparer.GetHashCode(Item2); } public override string ToString() { return string.Format("SymmetricPair: ({0} {1})", Item1, Item2); } } public static partial class DictionaryExtensions { // Extension methods for dictionaries of symmetric pairs. // https://unity3d.com/learn/tutorials/topics/scripting/extension-methods public static void Add<TKey, TValue>(this IDictionary<SymmetricPair<TKey>, TValue> dictionary, TKey item1, TKey item2, TValue value) { if (dictionary == null) throw new ArgumentNullException(); dictionary.Add(new SymmetricPair<TKey>(item1, item2), value); } public static void Set<TKey, TValue>(this IDictionary<SymmetricPair<TKey>, TValue> dictionary, TKey item1, TKey item2, TValue value) { if (dictionary == null) throw new ArgumentNullException(); dictionary[new SymmetricPair<TKey>(item1, item2)] = value; } public static bool Remove<TKey, TValue>(this IDictionary<SymmetricPair<TKey>, TValue> dictionary, TKey item1, TKey item2) { if (dictionary == null) throw new ArgumentNullException(); return dictionary.Remove(new SymmetricPair<TKey>(item1, item2)); } public static TValue Get<TKey, TValue>(this IDictionary<SymmetricPair<TKey>, TValue> dictionary, TKey item1, TKey item2) { if (dictionary == null) throw new ArgumentNullException(); return dictionary[new SymmetricPair<TKey>(item1, item2)]; } public static bool TryGetValue<TKey, TValue>(this IDictionary<SymmetricPair<TKey>, TValue> dictionary, TKey item1, TKey item2, out TValue value) { if (dictionary == null) throw new ArgumentNullException(); return dictionary.TryGetValue(new SymmetricPair<TKey>(item1, item2), out value); } } And do: var dictionary = new Dictionary<SymmetricPair<int>, string>(); dictionary.Set(1, 0, "hello"); Console.WriteLine(dictionary.Get(0, 1)); Sample [fiddle #2](https://dotnetfiddle.net/rd1UPn). In both cases your testing is now much simpler: you no longer need to validate your own dictionary implementation, you only need to validate your implementations of `GetHashCode()` and `Equals()`.