2009-07-23 2 views
92

Я знаю, что в BCL нет ни одного, но может ли кто-нибудь указать мне на хороший источник с открытым исходным кодом?Многоязычный словарь в C#?

By Multi Я имею в виду 2 ключа. ;-)

+2

Вам нужен ключ, который состоит из нескольких атрибутов или вы хотите, чтобы один и тот же ключ мог существовать более одного раза в одном словаре? Это разные. – Polaris878

+2

http://stackoverflow.com/questions/689940/hashtable-with-multidimensional-key-in-c –

+0

Возможно, вы захотите добавить пример использования, чтобы уточнить, что вы имеете в виду. –

ответ

5

В настоящее время я просто объединяю ключи в одну строку в качестве обходного пути. Конечно, это не будет работать на нестрочных клавишах. Хотелось бы также узнать ответ.

+0

Почему бы и нет .ToString() нестрочные ключи? – n8wrl

+3

Потому что для большинства классов .ToSting() будет одинаковым для всех значений (т. Е. Названия типов). Не все типы имеют допустимое строковое представление и т. Д. И т. Д. –

+0

Да, но вы можете обычно переопределять ToString в этих классах. – Badaro

49

Я использую Tuple в качестве ключей в Dictionary.

public class Tuple<T1, T2> { 
    public T1 Item1 { get; private set; } 
    public T2 Item2 { get; private set; } 

    // implementation details 
} 

Обязательно переопределить Equals и GetHashCode и определить operator!= и operator== в зависимости от обстоятельств. Вы можете развернуть Tuple для хранения большего количества предметов по мере необходимости. .NET 4.0 будет включать встроенный Tuple.

+2

Отметьте это сообщение в блоге о тестах производительности между несколькими «ключевыми» реализациями словаря [здесь] (http://www.fyslexicduck.com/2011/05/performance-tests-between-multiple.html) –

+0

@AronW Насколько я могу сказать, сообщение в блоге никогда не использует «Tuple» в качестве ключа? – flindeberg

27

Кортеж будет (есть) в .Net 4.0 До тех пор, вы можете также использовать

Dictionary<key1, Dictionary<key2, TypeObject>> 

или создания пользовательского класса коллекции, чтобы представить это ...

public class TwoKeyDictionary<K1, K2, T>: 
     Dictionary<K1, Dictionary<K2, T>> { } 

или с тремя ключами ...

public class ThreeKeyDictionary<K1, K2, K3, T> : 
    Dictionary<K1, Dictionary<K2, Dictionary<K3, T>>> { } 
+0

Блестящий ответ - это отлично работало для моих нужд. – HanClinto

6

Взгляните на Wintellect-х PowerCollections (CodePlex download). Я думаю, что их MultiDictionary делает что-то подобное.

Это словарь словарей, поэтому у вас есть 2 ключа для доступа к каждому объекту, ключ для основного словаря, чтобы получить требуемый дополнительный словарь, а затем второй ключ для дополнительного словаря, чтобы получить необходимый вам предмет. Это то, что вы имели ввиду?

+1

Их 'MultiDictionary <,>' позволяет назначать несколько значений одному ключу, а не иметь несколько ключей в этом смысле. – pbalaga

+1

, но вопрос OP такой расплывчатый, какой он может получить. Следовательно, +1 для другого брака. – nawfal

+0

@pbalaga - это правильно, PowerCollections не позволяет вам иметь два ключа (из-за этого занижены) –

2

Я думаю, вам понадобится класс Tuple2. Убедитесь, что это GetHashCode() и Equals() основаны на двух содержащихся элементах.

См Tuples in C#

6

Есть ли что-нибудь случилось с

new Dictionary<KeyValuePair<object, object>, object>
?

+3

Есть ли встроенная пара класс? –

+0

@MichaelDonohue: с .NET 4.0 существует класс ['Tuple'] (http://msdn.microsoft.com/en-us/library/system.tuple.aspx). –

+3

Да, что-то не так: KVP использует [ValueType.GetHashCode] (http://msdn.microsoft.com/en-us/library/system.valuetype.gethashcode.aspx) - «Если вы вызываете метод GetHashCode производного типа , возвращаемое значение вряд ли подходит для использования в качестве ключа в хеш-таблице ». KVP является совершенно неуместным выбором для ключа словаря и может привести к множеству столкновений. – bacar

58

Я уже использовал кортежи как jason в его ответе. Тем не менее, я предлагаю вам просто определить кортеж в качестве структуры:

public struct Tuple<T1, T2> { 
    public readonly T1 Item1; 
    public readonly T2 Item2; 
    public Tuple(T1 item1, T2 item2) { Item1 = item1; Item2 = item2;} 
} 

public static class Tuple { // for type-inference goodness. 
    public static Tuple<T1,T2> Create<T1,T2>(T1 item1, T2 item2) { 
     return new Tuple<T1,T2>(item1, item2); 
    } 
} 

Вы неизменность, .GetHashcode и .Equals бесплатно, что (в то время как вы ждете C# 4.0) для хорошо н просто ...

Один предупреждение однако: реализация по умолчанию GetHashcode (иногда) only considers the first field поэтому убедитесь, чтобы сделать первое поле самого разборчивого или реализовать GetHashcode себя (например, с использованием FieldwiseHasher.Hash(this) от ValueUtils), в противном случае вы, вероятно, столкнуться с проблемами масштабируемости.

Кроме того, вы избегаете ошибок, которые, как правило, усложняют вопросы (и если вы действительно хотите получить нули, вы просто делаете свой Tuple<> допустимым к нулю). Немного offtopic, я единственный, кто раздражен на уровне фреймового уровня поддержки непустых ссылок?Я работаю над большим проектом, а иногда нулевыми ползучами, где-то это действительно не должно быть - и hey presto, вы получаете исключение с нулевой ссылкой, но с трассировкой стека, указывающей на первое использование ссылки, а не на действительно ошибочный код ,

Конечно, .NET 4.0 довольно устарел; большинство из нас могут просто использовать кортеж .NET 4.0.

Edit:, чтобы обойти бедную GetHashCode реализации, .NET предоставляет для структур, которые я написал ValueUtils, который также позволяет использовать реальные имена для ключей многопрофильных; это означает, что вы могли бы написать что-то вроде:

sealed class MyValueObject : ValueObject<MyValueObject> { 
    public DayOfWeek day; 
    public string NamedPart; 
    //properties work fine too 
} 

... который, мы надеемся, делает его легче иметь человек считываемые имена для данных с семантикой значений, по крайней мере до some future version of C# implements proper tuples with named members; надеюсь, с достойными хэш-кодами ;-).

+2

Хорошая реклама по сравнению с решением типа value для кортежей в .NET: http://msdn.microsoft.com/en-us/magazine/dd942829.aspx#id0400060 – jason

+0

Действительно (после прочтения статьи), если вы используете default struct-implied .Equals и реализация .GetHashcode, кортеж с двойником, который является NaN, будет равен самому себе, хотя double.NaN! = double.NaN ... Я могу жить с этим. –

+0

В этой статье говорится, что они использовали ссылочный тип, так как не хотели вызывать путаницу из-за несогласованности семантики между типами структуры/ссылки, но я не вижу никаких аргументов относительно того, почему ссылочный тип был бы предпочтительнее; просто, что вы хотите, чтобы все кортежи были одного типа. –

4

Я искал для Google: http://www.codeproject.com/KB/recipes/multikey-dictionary.aspx. Я полагаю, что это основная функция по сравнению с использованием структуры, содержащей 2 ключа в обычном словаре, так это то, что вы можете позже ссылаться на один из ключей вместо того, чтобы иметь 2 ключа.

2

Не могли бы вы использовать Dictionary<TKey1,Dictionary<TKey2,TValue>>?

Можно даже создать подкласс этого:

public class DualKeyDictionary<TKey1,TKey2,TValue> : Dictionary<TKey1,Dictionary<TKey2,TValue>> 

EDIT: Это теперь дубликатом ответ. Он также ограничен в своей практичности. Хотя он «работает» и предоставляет возможность кода dict[key1][key2], есть много «обходных решений», чтобы заставить его «просто работать».

ОДНАКО: Только для пинков, можно реализовать словарь, тем не менее, но на данный момент он получает немного Verbose:

public class DualKeyDictionary<TKey1, TKey2, TValue> : Dictionary<TKey1, Dictionary<TKey2, TValue>> , IDictionary< object[], TValue > 
{ 
    #region IDictionary<object[],TValue> Members 

    void IDictionary<object[], TValue>.Add(object[] key, TValue value) 
    { 
     if (key == null || key.Length != 2) 
      throw new ArgumentException("Invalid Key"); 

     TKey1 key1 = key[0] as TKey1; 
     TKey2 key2 = key[1] as TKey2; 

     if (!ContainsKey(key1)) 
      Add(key1, new Dictionary<TKey2, TValue>()); 

     this[key1][key2] = value; 
    } 

    bool IDictionary<object[], TValue>.ContainsKey(object[] key) 
    { 
     if (key == null || key.Length != 2) 
      throw new ArgumentException("Invalid Key"); 

     TKey1 key1 = key[0] as TKey1; 
     TKey2 key2 = key[1] as TKey2; 

     if (!ContainsKey(key1)) 
      return false; 

     if (!this[key1].ContainsKey(key2)) 
      return false; 

     return true; 
    } 
+1

Вижу, Чарльз думает так же. Однако проблема с ними заключается в распределении. Это может быть зверь. – maxwellb

+0

+1 для именования, DualKey .. Ищем хорошее имя :) – nawfal

2

Вот конкретизированы пример класса пар, который может быть использован в качестве ключ к словарю.

public class Pair<T1, T2> { 
    public T1 Left { get; private set; } 
    public T2 Right { get; private set; } 

    public Pair(T1 t1, T2 t2) { 
     Left=t1; 
     Right=t2; 
    } 

    public override bool Equals(object obj) { 
     if(ReferenceEquals(null, obj)) return false; 
     if(ReferenceEquals(this, obj)) return true; 
     if(obj.GetType()!=typeof(Pair<T1, T2>)) return false; 
     return Equals((Pair<T1, T2>)obj); 
    } 

    public bool Equals(Pair<T1, T2> obj) { 
     if(ReferenceEquals(null, obj)) return false; 
     if(ReferenceEquals(this, obj)) return true; 
     return Equals(obj.Left, Left) && Equals(obj.Right, Right); 
    } 

    public override int GetHashCode() { 
     unchecked { 
     return (Left.GetHashCode()*397)^Right.GetHashCode(); 
     } 
    } 
    } 
6

Я часто использую это, потому что это коротко и обеспечивает синтаксический сахар, мне нужно ...

public class MultiKeyDictionary<T1, T2, T3> : Dictionary<T1, Dictionary<T2, T3>> 
{ 
    new public Dictionary<T2, T3> this[T1 key] 
    { 
     get 
     { 
      if (!ContainsKey(key)) 
       Add(key, new Dictionary<T2, T3>()); 

      Dictionary<T2, T3> returnObj; 
      TryGetValue(key, out returnObj); 

      return returnObj; 
     } 
    } 
} 

Чтобы использовать его:

dict[cat][fish] = 9000; 

где "Cat" ключ Безразлично» так и должно существовать.

+0

Я также должен отметить, что произвольно создавать дополнительные вложения с другим классом : Словарь > и т. д. Кроме того, я избегаю использовать его, но он хорошо очищает фанки вложенных словарей. – max

+0

Что такое хороший способ проверить, существуют ли ключи [cat] [fish] или [cat] [mouse]? –

+0

@goku_da_master 'dict [cat] .ContainsKey (mouse)' где, если cat не существует, вы всегда становитесь ложным, потому что он обновляется тогда. Если вы будете использовать его таким образом, я бы сравнил его, хотя это не будет очень оптимизированным способом сделать это. – max

9

Я написал и использовал это с успехом.

public class MultiKeyDictionary<K1, K2, V> : Dictionary<K1, Dictionary<K2, V>> { 

    public V this[K1 key1, K2 key2] { 
     get { 
      if (!ContainsKey(key1) || !this[key1].ContainsKey(key2)) 
       throw new ArgumentOutOfRangeException(); 
      return base[key1][key2]; 
     } 
     set { 
      if (!ContainsKey(key1)) 
       this[key1] = new Dictionary<K2, V>(); 
      this[key1][key2] = value; 
     } 
    } 

    public void Add(K1 key1, K2 key2, V value) { 
      if (!ContainsKey(key1)) 
       this[key1] = new Dictionary<K2, V>(); 
      this[key1][key2] = value; 
    } 

    public bool ContainsKey(K1 key1, K2 key2) { 
     return base.ContainsKey(key1) && this[key1].ContainsKey(key2); 
    } 

    public new IEnumerable<V> Values { 
     get { 
      return from baseDict in base.Values 
        from baseKey in baseDict.Keys 
        select baseDict[baseKey]; 
     } 
    } 

} 


public class MultiKeyDictionary<K1, K2, K3, V> : Dictionary<K1, MultiKeyDictionary<K2, K3, V>> { 
    public V this[K1 key1, K2 key2, K3 key3] { 
     get { 
      return ContainsKey(key1) ? this[key1][key2, key3] : default(V); 
     } 
     set { 
      if (!ContainsKey(key1)) 
       this[key1] = new MultiKeyDictionary<K2, K3, V>(); 
      this[key1][key2, key3] = value; 
     } 
    } 

    public bool ContainsKey(K1 key1, K2 key2, K3 key3) { 
     return base.ContainsKey(key1) && this[key1].ContainsKey(key2, key3); 
    } 
} 

public class MultiKeyDictionary<K1, K2, K3, K4, V> : Dictionary<K1, MultiKeyDictionary<K2, K3, K4, V>> { 
    public V this[K1 key1, K2 key2, K3 key3, K4 key4] { 
     get { 
      return ContainsKey(key1) ? this[key1][key2, key3, key4] : default(V); 
     } 
     set { 
      if (!ContainsKey(key1)) 
       this[key1] = new MultiKeyDictionary<K2, K3, K4, V>(); 
      this[key1][key2, key3, key4] = value; 
     } 
    } 

    public bool ContainsKey(K1 key1, K2 key2, K3 key3, K4 key4) { 
     return base.ContainsKey(key1) && this[key1].ContainsKey(key2, key3, key4); 
    } 
} 

public class MultiKeyDictionary<K1, K2, K3, K4, K5, V> : Dictionary<K1, MultiKeyDictionary<K2, K3, K4, K5, V>> { 
    public V this[K1 key1, K2 key2, K3 key3, K4 key4, K5 key5] { 
     get { 
      return ContainsKey(key1) ? this[key1][key2, key3, key4, key5] : default(V); 
     } 
     set { 
      if (!ContainsKey(key1)) 
       this[key1] = new MultiKeyDictionary<K2, K3, K4, K5, V>(); 
      this[key1][key2, key3, key4, key5] = value; 
     } 
    } 

    public bool ContainsKey(K1 key1, K2 key2, K3 key3, K4 key4, K5 key5) { 
     return base.ContainsKey(key1) && this[key1].ContainsKey(key2, key3, key4, key5); 
    } 
} 

public class MultiKeyDictionary<K1, K2, K3, K4, K5, K6, V> : Dictionary<K1, MultiKeyDictionary<K2, K3, K4, K5, K6, V>> { 
    public V this[K1 key1, K2 key2, K3 key3, K4 key4, K5 key5, K6 key6] { 
     get { 
      return ContainsKey(key1) ? this[key1][key2, key3, key4, key5, key6] : default(V); 
     } 
     set { 
      if (!ContainsKey(key1)) 
       this[key1] = new MultiKeyDictionary<K2, K3, K4, K5, K6, V>(); 
      this[key1][key2, key3, key4, key5, key6] = value; 
     } 
    } 
    public bool ContainsKey(K1 key1, K2 key2, K3 key3, K4 key4, K5 key5, K6 key6) { 
     return base.ContainsKey(key1) && this[key1].ContainsKey(key2, key3, key4, key5, key6); 
    } 
} 

public class MultiKeyDictionary<K1, K2, K3, K4, K5, K6, K7, V> : Dictionary<K1, MultiKeyDictionary<K2, K3, K4, K5, K6, K7, V>> { 
    public V this[K1 key1, K2 key2, K3 key3, K4 key4, K5 key5, K6 key6, K7 key7] { 
     get { 
      return ContainsKey(key1) ? this[key1][key2, key3, key4, key5, key6, key7] : default(V); 
     } 
     set { 
      if (!ContainsKey(key1)) 
       this[key1] = new MultiKeyDictionary<K2, K3, K4, K5, K6, K7, V>(); 
      this[key1][key2, key3, key4, key5, key6, key7] = value; 
     } 
    } 
    public bool ContainsKey(K1 key1, K2 key2, K3 key3, K4 key4, K5 key5, K6 key6, K7 key7) { 
     return base.ContainsKey(key1) && this[key1].ContainsKey(key2, key3, key4, key5, key6, key7); 
    } 
} 

public class MultiKeyDictionary<K1, K2, K3, K4, K5, K6, K7, K8, V> : Dictionary<K1, MultiKeyDictionary<K2, K3, K4, K5, K6, K7, K8, V>> { 
    public V this[K1 key1, K2 key2, K3 key3, K4 key4, K5 key5, K6 key6, K7 key7, K8 key8] { 
     get { 
      return ContainsKey(key1) ? this[key1][key2, key3, key4, key5, key6, key7, key8] : default(V); 
     } 
     set { 
      if (!ContainsKey(key1)) 
       this[key1] = new MultiKeyDictionary<K2, K3, K4, K5, K6, K7, K8, V>(); 
      this[key1][key2, key3, key4, key5, key6, key7, key8] = value; 
     } 
    } 
    public bool ContainsKey(K1 key1, K2 key2, K3 key3, K4 key4, K5 key5, K6 key6, K7 key7, K8 key8) { 
     return base.ContainsKey(key1) && this[key1].ContainsKey(key2, key3, key4, key5, key6, key7, key8); 
    } 
} 

public class MultiKeyDictionary<K1, K2, K3, K4, K5, K6, K7, K8, K9, V> : Dictionary<K1, MultiKeyDictionary<K2, K3, K4, K5, K6, K7, K8, K9, V>> { 
    public V this[K1 key1, K2 key2, K3 key3, K4 key4, K5 key5, K6 key6, K7 key7, K8 key8, K9 key9] { 
     get { 
      return ContainsKey(key1) ? this[key1][key2, key3, key4, key5, key6, key7, key8, key9] : default(V); 
     } 
     set { 
      if (!ContainsKey(key1)) 
       this[key1] = new MultiKeyDictionary<K2, K3, K4, K5, K6, K7, K8, K9, V>(); 
      this[key1][key2, key3, key4, key5, key6, key7, key8, key9] = value; 
     } 
    } 
    public bool ContainsKey(K1 key1, K2 key2, K3 key3, K4 key4, K5 key5, K6 key6, K7 key7, K8 key8, K9 key9) { 
     return base.ContainsKey(key1) && this[key1].ContainsKey(key2, key3, key4, key5, key6, key7, key8, key9); 
    } 
} 

public class MultiKeyDictionary<K1, K2, K3, K4, K5, K6, K7, K8, K9, K10, V> : Dictionary<K1, MultiKeyDictionary<K2, K3, K4, K5, K6, K7, K8, K9, K10, V>> { 
    public V this[K1 key1, K2 key2, K3 key3, K4 key4, K5 key5, K6 key6, K7 key7, K8 key8, K9 key9, K10 key10] { 
     get { 
      return ContainsKey(key1) ? this[key1][key2, key3, key4, key5, key6, key7, key8, key9, key10] : default(V); 
     } 
     set { 
      if (!ContainsKey(key1)) 
       this[key1] = new MultiKeyDictionary<K2, K3, K4, K5, K6, K7, K8, K9, K10, V>(); 
      this[key1][key2, key3, key4, key5, key6, key7, key8, key9, key10] = value; 
     } 
    } 
    public bool ContainsKey(K1 key1, K2 key2, K3 key3, K4 key4, K5 key5, K6 key6, K7 key7, K8 key8, K9 key9, K10 key10) { 
     return base.ContainsKey(key1) && this[key1].ContainsKey(key2, key3, key4, key5, key6, key7, key8, key9, key10); 
    } 
} 

public class MultiKeyDictionary<K1, K2, K3, K4, K5, K6, K7, K8, K9, K10, K11, V> : Dictionary<K1, MultiKeyDictionary<K2, K3, K4, K5, K6, K7, K8, K9, K10, K11, V>> { 
    public V this[K1 key1, K2 key2, K3 key3, K4 key4, K5 key5, K6 key6, K7 key7, K8 key8, K9 key9, K10 key10, K11 key11] { 
     get { 
      return ContainsKey(key1) ? this[key1][key2, key3, key4, key5, key6, key7, key8, key9, key10, key11] : default(V); 
     } 
     set { 
      if (!ContainsKey(key1)) 
       this[key1] = new MultiKeyDictionary<K2, K3, K4, K5, K6, K7, K8, K9, K10, K11, V>(); 
      this[key1][key2, key3, key4, key5, key6, key7, key8, key9, key10, key11] = value; 
     } 
    } 
    public bool ContainsKey(K1 key1, K2 key2, K3 key3, K4 key4, K5 key5, K6 key6, K7 key7, K8 key8, K9 key9, K10 key10, K11 key11) { 
     return base.ContainsKey(key1) && this[key1].ContainsKey(key2, key3, key4, key5, key6, key7, key8, key9, key10, key11); 
    } 
} 
+0

Я написал расширение для ToMultiKeyDictionary() для этого ответа и [отправил его как ответ ниже] (https://stackoverflow.com/a/21270886/435383) – katbyte

1

Вот моя реализация. Я хотел что-то скрывать от реализации концепции Tuple.

public class TwoKeyDictionary<TKey1, TKey2, TValue> : Dictionary<TwoKey<TKey1, TKey2>, TValue> 
    { 
    public static TwoKey<TKey1, TKey2> Key(TKey1 key1, TKey2 key2) 
    { 
     return new TwoKey<TKey1, TKey2>(key1, key2); 
    } 

    public TValue this[TKey1 key1, TKey2 key2] 
    { 
     get { return this[Key(key1, key2)]; } 
     set { this[Key(key1, key2)] = value; } 
    } 

    public void Add(TKey1 key1, TKey2 key2, TValue value) 
    { 
     Add(Key(key1, key2), value); 
    } 

    public bool ContainsKey(TKey1 key1, TKey2 key2) 
    { 
     return ContainsKey(Key(key1, key2)); 
    } 
    } 

    public class TwoKey<TKey1, TKey2> : Tuple<TKey1, TKey2> 
    { 
    public TwoKey(TKey1 item1, TKey2 item2) : base(item1, item2) { } 

    public override string ToString() 
    { 
     return string.Format("({0},{1})", Item1, Item2); 
    } 
    } 

Это помогает держит использование выглядит как словарь

item.Add(1, "D", 5.6); 

value = item[1, "D"]; 
+0

как перебирать все? – MobileMon

1

Если кто-то ищет ToMultiKeyDictionary() здесь является реализация, которая должна работать с большинством ответов здесь (на основе Herman's):

public static class Extensions_MultiKeyDictionary { 

    public static MultiKeyDictionary<K1, K2, V> ToMultiKeyDictionary<S, K1, K2, V>(this IEnumerable<S> items, Func<S, K1> key1, Func<S, K2> key2, Func<S, V> value) { 
     var dict = new MultiKeyDictionary<K1, K2, V>(); 
     foreach (S i in items) { 
      dict.Add(key1(i), key2(i), value(i)); 
     } 
     return dict; 
    } 

    public static MultiKeyDictionary<K1, K2, K3, V> ToMultiKeyDictionary<S, K1, K2, K3, V>(this IEnumerable<S> items, Func<S, K1> key1, Func<S, K2> key2, Func<S, K3> key3, Func<S, V> value) { 
     var dict = new MultiKeyDictionary<K1, K2, K3, V>(); 
     foreach (S i in items) { 
      dict.Add(key1(i), key2(i), key3(i), value(i)); 
     } 
     return dict; 
    } 
} 
14

Много хороших решений здесь, Что я здесь отсутствует является реализация на основе построения в Tuple, поэтому я написал сам.

Поскольку он просто наследуется от Dictionary<Tuple<T1,T2>, T>, вы всегда можете использовать оба способа.

var dict = new Dictionary<int, int, Row>(); 
var row = new Row(); 
dict.Add(1, 2, row); 
dict.Add(Tuple.Create(1, 2, row)); 
dict.Add(new Tuple<int, int>(1, 2)); 

вот код.

public class Dictionary<TKey1,TKey2,TValue> : Dictionary<Tuple<TKey1, TKey2>, TValue>, IDictionary<Tuple<TKey1, TKey2>, TValue> 
{ 

    public TValue this[TKey1 key1, TKey2 key2] 
    { 
     get { return base[Tuple.Create(key1, key2)]; } 
     set { base[Tuple.Create(key1, key2)] = value; } 
    } 

    public void Add(TKey1 key1, TKey2 key2, TValue value) 
    { 
     base.Add(Tuple.Create(key1, key2), value); 
    } 

    public bool ContainsKey(TKey1 key1, TKey2 key2) 
    { 
     return base.ContainsKey(Tuple.Create(key1, key2)); 
    } 
} 

Обратите внимание, что эта реализация зависит от Tuple.Equals() реализация сама по себе:

http://msdn.microsoft.com/en-us/library/dd270346(v=vs.110).aspx

Параметр OBJ считается равным текущему экземпляру при следующих условиях:

  • Это объект Tuple.
  • Его два компонента имеют те же типы, что и текущий экземпляр.
  • Его две составляющие равны характеристикам текущего экземпляра. Равенство определяется стандартным сопоставлением равенства объектов для каждого компонента.
+0

Простой и хорошо работает, спасибо. – 56ka

+0

Очень приятное решение –

0

Вот еще один пример использования класса Tuple с Dictionary.

 // Setup Dictionary 
    Dictionary<Tuple<string, string>, string> testDictionary = new Dictionary<Tuple<string, string>, string> 
    { 
     {new Tuple<string, string>("key1","key2"), "value1"}, 
     {new Tuple<string, string>("key1","key3"), "value2"}, 
     {new Tuple<string, string>("key2","key3"), "value3"} 
    }; 
    //Query Dictionary 
    public string FindValue(string stuff1, string stuff2) 
    { 
     return testDictionary[Tuple.Create(stuff1, stuff2)]; 
    }