Given that you are looking for a partial key match, you will not be able to accomplish this with a single dictionary. That's why:
Suppose you have a class of "rules". We will call it the "Key". You can create it this way:
Key.Create(0) // this "rule" would match any query key starting with 0 (eg, {0}, {0, 1}, or {0, 1, 9, 2, 23, 243})
Now suppose you want to query it using some kind of "fact" or "query key" class. Since you are querying the dictionary using the value type that was used as the key during the add operation, you will have to reuse the same type:
Key.Create(0, 2, 13) // this fact should be matched by rules {0}, {0,2} or {0, 2, 13}
Now you will try to get the value:
var value = map[Key.Create(0, 2, 13)]
The Key class can override Equals to provide partial matching. However, the dictionary will first use the hash code, and the hash code for Key.Create (0, 2, 13) will never match the key identifier Key.Create (0). You cannot get around this using any type of base / derived type.
The best option is probably to descend your own class. Something like this should do:
class ResultMap { public void Add(int[] key, string value) { Debug.Assert(key != null); Debug.Assert(key.Length > 0); var currentMap = _root; foreach (var i in key.Take(key.Length - 1)) { object levelValue; if (currentMap.TryGetValue(i, out levelValue)) { currentMap = levelValue as Dictionary<int, object>; if (currentMap == null) throw new Exception("A rule is already defined for this key."); } else { var newMap = new Dictionary<int, object>(); currentMap.Add(i, newMap); currentMap = newMap; } } var leaf = key[key.Length - 1]; if (currentMap.ContainsKey(leaf)) throw new Exception("A rule is already defined for this key."); currentMap.Add(leaf, value); } public string TryGetValue(params int[] key) { Debug.Assert(key != null); Debug.Assert(key.Length > 0); var currentMap = _root; foreach (var i in key) { object levelValue; if (!currentMap.TryGetValue(i, out levelValue)) return null; currentMap = levelValue as Dictionary<int, object>; if (currentMap == null) return (string) levelValue; } return null; } private readonly Dictionary<int, object> _root = new Dictionary<int, object>(); }
Here's the unit test:
public void Test() { var resultMap = new ResultMap(); resultMap.Add(new[] {0}, "a0"); resultMap.Add(new[] {1, 0}, "b0"); resultMap.Add(new[] {1, 1, 0}, "c0"); resultMap.Add(new[] {1, 1, 1}, "c1"); resultMap.Add(new[] {1, 2}, "b2"); resultMap.Add(new[] {2}, "a2"); Debug.Assert("a0" == resultMap.TryGetValue(0)); Debug.Assert("a0" == resultMap.TryGetValue(0, 0)); Debug.Assert("a0" == resultMap.TryGetValue(0, 1)); Debug.Assert("a0" == resultMap.TryGetValue(0, 2)); Debug.Assert("a0" == resultMap.TryGetValue(0, 0, 0)); Debug.Assert("a0" == resultMap.TryGetValue(0, 0, 1)); Debug.Assert("a0" == resultMap.TryGetValue(0, 0, 2)); Debug.Assert("a0" == resultMap.TryGetValue(0, 1, 0)); Debug.Assert("a0" == resultMap.TryGetValue(0, 1, 1)); Debug.Assert("a0" == resultMap.TryGetValue(0, 1, 2)); Debug.Assert("a0" == resultMap.TryGetValue(0, 2, 0)); Debug.Assert("a0" == resultMap.TryGetValue(0, 2, 1)); Debug.Assert("a0" == resultMap.TryGetValue(0, 2, 2)); Debug.Assert(null == resultMap.TryGetValue(1)); Debug.Assert("b0" == resultMap.TryGetValue(1, 0)); Debug.Assert(null == resultMap.TryGetValue(1, 1)); Debug.Assert("b2" == resultMap.TryGetValue(1, 2)); Debug.Assert("b0" == resultMap.TryGetValue(1, 0, 0)); Debug.Assert("b0" == resultMap.TryGetValue(1, 0, 1)); Debug.Assert("b0" == resultMap.TryGetValue(1, 0, 2)); Debug.Assert("c0" == resultMap.TryGetValue(1, 1, 0)); Debug.Assert("c1" == resultMap.TryGetValue(1, 1, 1)); Debug.Assert(null == resultMap.TryGetValue(1, 1, 2)); Debug.Assert("b2" == resultMap.TryGetValue(1, 2, 0)); Debug.Assert("b2" == resultMap.TryGetValue(1, 2, 1)); Debug.Assert("b2" == resultMap.TryGetValue(1, 2, 2)); Debug.Assert("a2" == resultMap.TryGetValue(2)); Debug.Assert("a2" == resultMap.TryGetValue(2, 0)); Debug.Assert("a2" == resultMap.TryGetValue(2, 1)); Debug.Assert("a2" == resultMap.TryGetValue(2, 2)); Debug.Assert("a2" == resultMap.TryGetValue(2, 0, 0)); Debug.Assert("a2" == resultMap.TryGetValue(2, 0, 1)); Debug.Assert("a2" == resultMap.TryGetValue(2, 0, 2)); Debug.Assert("a2" == resultMap.TryGetValue(2, 1, 0)); Debug.Assert("a2" == resultMap.TryGetValue(2, 1, 1)); Debug.Assert("a2" == resultMap.TryGetValue(2, 1, 2)); Debug.Assert("a2" == resultMap.TryGetValue(2, 2, 0)); Debug.Assert("a2" == resultMap.TryGetValue(2, 2, 1)); Debug.Assert("a2" == resultMap.TryGetValue(2, 2, 2)); }