嗯,创建一个可以存储密钥的自己的三键结构是一个很好的计划,但首先让我们来看看source code的KeyValuePair
结构。
现在让我们来定义自己的TripleKey
结构:
[Serializable]
public struct TripleKey<TKeyA, TKeyB, TKeyC>
{
public TKeyA KeyA { get; };
public TKeyB KeyB { get; };
public TKeyC KeyC { get; };
public TripleKey(TKeyA keyA, TKeyB keyB, TKeyC keyC)
{
this.KeyA = keyA;
this.KeyB = keyB;
this.KeyC = keyC;
}
// this code is almost the same as it is in Microsoft implementation
public override string ToString()
{
var sBuilder = new StringBuilder();
sBuilder.Append('(');
if (KeyA != null)
{
sBuilder.Append(KeyA.ToString());
}
sBuilder.Append(", ");
if (KeyB != null)
{
sBuilder.Append(KeyB.ToString());
}
sBuilder.Append(", ");
if (KeyC != null)
{
sBuilder.Append(KeyC.ToString());
}
sBuilder.Append(')');
return sBuilder.ToString();
}
}
public static class TripleKey
{
public static TripleKey<TKeyA, TKeyB, TKeyC> Create<TKeyA, TKeyB, TKeyC>(TKeyA keyA, TKeyB keyB, TKeyC keyC)
{
return new TripleKey<TKeyA, TKeyB, TKeyC>(keyA, keyB, keyC);
}
}
public class MultiKeyDictionary<TKeyA, TKeyB, TKeyC, TValue> : Dictionary<TripleKey<TKeyA, TKeyB, TKeyC>, TValue>
{
public TValue this[TKeyA keyA, TKeyB keyB, TKeyC keyC]
{
get
{
var key = TripleKey.Create(keyA, keyB, keyC);
return base.ContainsKey(key) ? base[key] : default(TValue);
}
set
{
var key = TripleKey.Create(keyA, keyB, keyC);
if (!ContainsKey(key))
base.Add(key, value);
this[key] = value;
}
}
public bool ContainsKey(TKeyA keyA, TKeyB keyB, TKeyC keyC)
{
var key = TripleKey.Create(keyA, keyB, keyC);
return base.ContainsKey(key);
}
public void Add(TKeyA keyA, TKeyB keyB, TKeyC keyC, TValue value)
{
base.Add(TripleKey.Create(keyA, keyB, keyC), value);
}
}
一个关于结构类型最大的事情之一是,因为他们从ValueType
继承他们继承其实现GetHashCode
方法。这个实现的工作方式是,对于任何两个具有相同值的结构,hashcode总是匹配的(然而,如果两个hashcode匹配,则百分之百不保证所有值都相同)。
现在我们已经解决了,我们准备使用MultiKeyDictionary<TKeyA, TKeyB, TKeyC, TValue>
或简单的Dictionary<TripleKey<TKeyA, TKeyB, TKeyC>, TValue>
。
简单的例子:
var myDict = new MultiKeyDictionary<string, double, double, string>
{
{"Goodbye", 0.55, 9.00, "yaya"} // collection initializer works fine
};
myDict.Add("Hello", 1.11, 2.99, "hi");
Console.WriteLine(myDict.ContainsKey("Hello", 1.11, 2.99)); // true
Console.WriteLine(myDict.ContainsKey("a", 1.11, 2.99)); // false
Console.WriteLine(myDict["Hello", 1.11, 2.99]); // hi
myDict.Add(TripleKey.Create("Hello", 1.11, 2.99), "gh"); // bang! exception,
// key already exists
P.S.
正如ScottChamberlain指出的那样,ValueType
的implementation of GetHashcode
方法有其优点和缺点。它使用反射,可能会导致性能问题,因此最好不要依赖struct的GetHashCode
实现,并用自定义实现覆盖它。
Eric Lippert的博客中有一篇很好的文章,名为“Guidelines and rules for GetHashCode”。
工作例如:https://dotnetfiddle.net/y1a30V
使用'Dictionary,YourClass>'一个简单的解决方案或者你可以使用'List >' –
Monah
@HadiHassan:在问题中提到 - “Tuple”类在C#4之前不可用。 –
@GaryMcGill我认为3个键的Tuple可以很容易地完成,但我不认为要建立一个数据结构(字典字典的字典)来表示3个键的数据在这里是一个不错的选择,(使用或从头开始实现具有3个键和一个对象值的元组类更简单直接)。我没有仔细阅读这个问题,直接阅读下面的代码。 – Monah