2013-08-17 1 views
2

Мне нужен тип Tuple типа или KeyValuePair и с возможностью установки его значений (изменяемый тип). AnyIdeas существующих Generics реализовать эту ситуацию?Нужна помощь в DataStructure, например, Tuple или keyValuePair, но изменяемый тип

(Словарь кажется мне чем-то вроде overkill forr для моей цели) Я тоже могу написать свой собственный класс, но я предполагаю, что уже реализован некоторый изменяемый тип keyValue.

Thanks

ответ

0

Нет, не существует. Если вы не считаете, что object[] будет одним :-)

Обратите внимание, что реализация MutableTuple<T1, ...> довольно проста.

Полная реализация MutableTuple<T1, T2, T3>, почти эквивалентно Tuple<T1, T2, T3> (различные интерфейсы реализованы публично и не в частном порядке) (частично на основе реализации Mono из Tuple<>)

public static class MutableTuple 
{ 
    public static MutableTuple<T1, T2, T3> Create<T1, T2, T3>(T1 item1, T2 item2, T3 item3) 
    { 
     return new MutableTuple<T1, T2, T3>(item1, item2, item3); 
    } 
} 

[Serializable] 
public class MutableTuple<T1, T2, T3> : IComparable, IStructuralEquatable, IStructuralComparable 
{ 
    public T1 Item1 { get; set; } 
    public T2 Item2 { get; set; } 
    public T3 Item3 { get; set; } 

    public MutableTuple(T1 item1, T2 item2, T3 item3) 
    { 
     this.Item1 = item1; 
     this.Item2 = item2; 
     this.Item3 = item3; 
    } 

    public override bool Equals(object obj) 
    { 
     return this.Equals(obj, EqualityComparer<object>.Default); 
    } 

    public override int GetHashCode() 
    { 
     return this.GetHashCode(EqualityComparer<object>.Default); 
    } 

    public override string ToString() 
    { 
     var sb = new StringBuilder(); 

     sb.Append(this.Item1); 
     sb.Append(", "); 
     sb.Append(this.Item2); 
     sb.Append(", "); 
     sb.Append(this.Item3); 
     sb.Append(")"); 

     return sb.ToString(); 
    } 

    public int CompareTo(object obj) 
    { 
     return this.CompareTo(obj, Comparer<object>.Default); 
    } 

    public bool Equals(object obj, IEqualityComparer comparer) 
    { 
     if (obj == null) 
     { 
      return false; 
     } 

     var tuple = obj as MutableTuple<T1, T2, T3>; 
     return tuple != null && (comparer.Equals(this.Item1, tuple.Item1) && comparer.Equals(this.Item2, tuple.Item2)) && comparer.Equals(this.Item3, tuple.Item3); 
    } 

    public int GetHashCode(IEqualityComparer comparer) 
    { 
     unchecked 
     { 
      int hash = 17; 

      hash = (hash * 23) + comparer.GetHashCode(this.Item1); 
      hash = (hash * 23) + comparer.GetHashCode(this.Item2); 
      hash = (hash * 23) + comparer.GetHashCode(this.Item3); 

      return hash; 
     } 
    } 

    public int CompareTo(object obj, IComparer comparer) 
    { 
     if (obj == null) 
     { 
      return 1; 
     } 

     var other = obj as MutableTuple<T1, T2, T3>; 

     if (other == null) 
     { 
      throw new ArgumentException(); 
     } 

     int res = comparer.Compare(this.Item1, other.Item1); 

     if (res != 0) 
     { 
      return res; 
     } 

     res = comparer.Compare(this.Item2, other.Item2); 

     if (res != 0) 
     { 
      return res; 
     } 

     res = comparer.Compare(this.Item3, other.Item3); 

     return res; 
    } 
} 
+1

Там существует [ 'DictionaryEntry'] (http://msdn.microsoft.com/en-us/library/system.collections.dictionaryentry. aspx), который является изменяемой парой, но он имеет две проблемы: (1) Он не является универсальным/безопасным по типу. (2) Это тип изменяемого значения. –

+0

@JeppeStigNielsen Вы правы ... Я не знал. Мы могли бы даже добавить, что одна проблема состоит в том, что это 'struct' :-) Для Tuple они очень много думали и распускали' class'es. А второй (это изменяемый тип значения) - это функция, а не ошибка :-) – xanatos

+0

Хороший полный ответ. Несколько комментариев: 1) почему вы используете не общий аналог для равенства и хеш-кодов, чтобы вызвать бокс? 2) Стоит ли построитель строк вместо 6 конкатенаций строк? 3) 'Mutuple' было бы лучшим наименованием: D – nawfal

1
public class MutableKeyValuePair<TKey, TValue> 
{ 
    public TKey Key { get; set; } 
    public TValue Value { get; set; } 
} 

Вот так.

2

Проблема с изменением заключается в том, что вы можете очень легко в конечном итоге ссылаться на один и тот же кортеж несколько раз, когда вы меняете значение в одном месте, оно также будет меняться в других местах, где вы этого не ожидаете. Поэтому, если вы используете mutable tubles, вам нужно быть очень строгим относительно клонирования кортежа в соответствующих местах, например, если вы поместите его в коллекцию.

Но изменчивая кортеж будет выглядеть примерно так:

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

    public MutableTuple(T1 item1, T2 item2) { 
     Item1 = item1; 
     Item2 = item2; 
    } 
} 
+0

Не совсем достаточно. По умолчанию кортежи имеют реализации равенства и хеш-кода. – nawfal