嗯,創建一個可以存儲密鑰的自己的三鍵結構是一個很好的計劃,但首先讓我們來看看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