If you are using .NET 4, you can use the Tuple class:
Dictionary<Tuple<string, string>, TValue> dict = new ...
If you are not using .NET 4, you must create your own type to save this.
You can use KeyValuePair , but it inherits the appropriate methods from the base value type and thus relies heavily on reflection. This has performance implications (see bottom of answer.)
For KeyValuePair:
Dictionary<KeyValuePair<string, string>, TValue> dict = new ...
Here is a generic type that you can use if you don't want to cook it yourself:
public struct SimpleTuple<TValue1, TValue2> { private readonly TValue1 _Value1; private readonly TValue2 _Value2; public SimpleTuple(TValue1 value1, TValue2 value2) { _Value1 = value1; _Value2 = value2; } public TValue1 Value1 { get { return _Value1; } } public TValue2 Value2 { get { return _Value2; } } public int GetHashCode() { unchecked { int result = 37; result *= 23; if Value1 != null) result += Value1.GetHashCode(); result *= 23; if (Value2 != null) result += Value2.GetHashCode(); return result; } } public override bool Equals(object obj) { if (obj == null) return false; if (obj.GetType() != typeof(SimpleTuple<TValue1, TValue2>)) return false; var other = (SimpleTuple<TValue1, TValue2>)obj; return Equals(other.Value1, Value1) && Equals(other.Value2, Value2); } }
Of course, KeyValuePair also works on .NET 4.0 just like good bad.
As for collisions, it depends on what you mean. A hash table (a dictionary uses the internal structure of a hash table) always has the ability to get key collisions, but that's where the comparison comes into play. If two different keys generate the same hash code, the dictionary class will compare the key with the key to see if they are really the same value, or just create the same hash code.
The reason that a hash table will always have the possibility of collision is best described using the pidgeonhole principle (Wikipedia) .
This means that if you encounter two different keys, this will not be a problem, they will both be stored with the correct values in the dictionary.
Of course, if you create the same key twice, the dictionary will consider it the same key and either will not be able to add a new value or overwrite the existing one (depending on how you ask it to add the value).
This will throw an exception for duplicate keys:
dict.Add(key, value);
This will add or overwrite the existing one:
dict[key] = value;
In response to Ani's comment, I wrote the following simple test script for LINQPad . Output:
KeyValuePair: 975ms
MyKeyValuePair: 52ms
script:
void Main() { const int iterations = 10 * 1000 * 1000; // JIT preheat Test1(1); Test2(1); Stopwatch sw = Stopwatch.StartNew(); Test1(iterations); sw.Stop(); Debug.WriteLine("KeyValuePair: " + sw.ElapsedMilliseconds + "ms"); sw = Stopwatch.StartNew(); Test2(iterations); sw.Stop(); Debug.WriteLine("MyKeyValuePair: " + sw.ElapsedMilliseconds + "ms"); } public static void Test1(int iterations) { for (int index = 0; index < iterations; index++) { var kvp = new KeyValuePair<int, int>(index, index); kvp.GetHashCode(); } } public static void Test2(int iterations) { for (int index = 0; index < iterations; index++) { var kvp = new MyKeyValuePair<int, int>(index, index); kvp.GetHashCode(); } } public struct MyKeyValuePair<TKey, TValue> { private readonly TKey _Key; private readonly TValue _Value; public MyKeyValuePair(TKey key, TValue value) { _Key = key; _Value = value; } public TKey Key { get { return _Key; } } public TValue Value { get { return _Value; } } public int GetHashCode() { unchecked { int result = 37; result *= 23; if (Key != null) result += Key.GetHashCode(); result *= 23; if (Value != null) result += Value.GetHashCode(); return result; } } public override bool Equals(object obj) { if (obj == null) return false; if (obj.GetType() != typeof(MyKeyValuePair<TKey, TValue>)) return false; var other = (MyKeyValuePair<TKey, TValue>)obj; return Equals(other.Key, Key) && Equals(other.Value, Value); } }