鉴于您正在寻找键的部分匹配,您将无法使用单个字典完成此操作。原因如下:
假设你有某种“规则”类。我们称之为“钥匙”。你可以像这样实例化它:
Key.Create(0) // this "rule" would match any query key starting with 0 (e.g., {0}, {0, 1}, or {0, 1, 9, 2, 23, 243})
现在假设您想使用某种“事实”或“查询键”类来查询它。由于您使用在 Add 操作期间用作键的值类型来查询字典,因此您必须重用相同的类型:
Key.Create(0, 2, 13) // this fact should be matched by rules {0}, {0,2} or {0, 2, 13}
现在您将尝试获取该值:
var value = map[Key.Create(0, 2, 13)]
Key 类可以覆盖 Equals 以允许部分键匹配。但是,字典将首先使用哈希码,并且 Key.Create(0, 2, 13) 的哈希码永远不会匹配 Key.Create(0) 的哈希码。您也无法通过使用任何类型的基/派生类型来解决此问题。
最好的选择可能是推出自己的课程。这样的事情应该做:
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>();
}
这是一个单元测试:
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));
}