Если вы используете .NET 4, вы можете использовать класс Tuple :
Dictionary<Tuple<string, string>, TValue> dict = new ...
Если вы не используете .NET 4, вы должны создать свой собственный тип для хранения этого.
Вы можете использовать структуру KeyValuePair , но она наследует соответствующие методы от типа базового значения и, таким образом, сильно зависит от отражения. Это влияет на производительность (см. Нижнюю часть ответа.)
Для KeyValuePair:
Dictionary<KeyValuePair<string, string>, TValue> dict = new ...
Вот общий тип, который вы можете использовать, если не хотите готовить его самостоятельно:
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);
}
}
Конечно, KeyValuePair также работает в .NET 4.0 так же, как хорошо плохо.
Что касается столкновений, то это зависит от того, что вы имеете в виду. Хеш-таблица (словарь использует внутреннюю структуру хеш-таблицы) всегда имеет возможность получить ключевые коллизии, но здесь начинается сравнение. Если два разных ключа генерируют один и тот же хеш-код, класс словаря сравнивает ключ с ключом, чтобы определить, действительно ли они имеют одинаковые значения, или просто выдает одинаковый хеш-код.
Причины, по которым в хеш-таблице всегда есть вероятность столкновений, лучше всего описать с помощью принципа pidgeonhole (Википедия) .
Это означает, что если два разных ключа вызовут коллизию, это не будет проблемой, они оба будут сохранены с правильными значениями в словаре.
Конечно, если вы создадите один и тот же ключ дважды, словарь будет считать его одним и тем же ключом и либо не сможет добавить новое значение, либо перезапишет существующее (в зависимости от того, как вы попросите его добавить значение).
Это вызовет исключение для дубликатов ключей:
dict.Add(key, value);
Это добавит или перезапишет существующее:
dict[key] = value;
В ответ на комментарий Ани я написал следующий простой тестовый скрипт для LINQPad . Вывод был:
KeyValuePair: 975ms
MyKeyValuePair: 52ms
сценарий:
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);
}
}