2010-06-28 16 views
42

Estaba pensando en usar la clase Tuple para almacenar 2 enteros de información (StartAddress, EndAddress) que necesito en mi programa.¿Por qué los artículos de Tuple son de solo lectura?

Pero descubrí que los artículos Tuple son de solo lectura, así que si necesito establecer un valor para un artículo, necesito volver a crear una instancia de Tuple.

¿Cuál es el motivo de esta decisión de diseño?

+1

Creo que en la programación de OO, Tuple suele ser simplemente un desarrollador perezoso para describir sus estructuras de datos. En la programación funcional, sin embargo, es el becerro de oro. No estoy diciendo que ninguno sea bueno o malo y también soy flojo algunas veces. Solo que puede haber diferentes mejores prácticas para diferentes casos de uso. – Rbjz

Respuesta

41

Tuplas se originó en functional programming. En la programación (puramente) funcional, todo es inmutable por diseño: una determinada variable solo tiene una única definición en todo momento, como en las matemáticas. Los diseñadores de .NET sabiamente siguieron el mismo principio al integrar el estilo funcional en C# /. NET, a pesar de que en última instancia era un lenguaje primordialmente imperativo (¿híbrido?).

Nota: Aunque sospecho que el hecho de que las tuplas sean inmutables realmente no hace su tarea mucho más difícil, también hay tipos anónimos (o tal vez simplemente una estructura simple) que podría querer usar.

+9

Son los diseñadores de CLR, no los diseñadores de C#. System.Tuple en .NET 4 también se utilizan implícitamente por F #. –

+4

Fueron más los desarrolladores de BCL que los diseñadores de C#: hubo una decisión, ahora que F # se unía al establo de los lenguajes .Net para tener un tipo de Tuple unificado. –

+1

Ahh el inevitable pedante. Además, F # usó sus propios tipos de tuplas antes de .NET 4.0, de todos modos es irrelevante. – Noldorin

-1

Obtuviste solo los captadores de las propiedades de ItemX, eso es correcto, pero encontré una manera de primero instanciar un tupple con valores vacíos y rellenarlos después.

Si haces algo como esto:

Dictionary <string, Tuple<string, string>> mydic = new Dictionary<string,Tuple<string,string>>(); 
Tuple<string, string> tplTemp = new Tuple<string, string>("", ""); 
mydic.TryGetValue("akey", out tplTemp); 

El tplTemp pasa como un parámetro de salida tendrá sus valores de 2 artículos de la colección. Así que esa es una manera de hacerlo en caso de que esto pueda ayudar a alguien.

+2

Esta no es una forma de llenar una Tupla con valores. Todo lo que ha hecho es crear un segundo Tuple y asignarle tplTemp a su valor. Tu código es equivalente a simplemente hacer: tplTemp = new Tuple ("some", "values"); – gerrard00

1

Me pregunto por qué no hay tal cosa como esta. Sin embargo, es lo que prefiero usar.

namespace System 
{ 
    /// <summary> 
    /// Helper so we can call some tuple methods recursively without knowing the underlying types. 
    /// </summary> 
    internal interface IWTuple 
    { 
     string ToString(StringBuilder sb); 
     int GetHashCode(IEqualityComparer comparer); 
     int Size { get; } 
    } 

    /// <summary> 
    /// Represents a writable 2-tuple, or pair. 
    /// </summary> 
    /// <typeparam name="T1">The type of the tuple's first component.</typeparam> 
    /// <typeparam name="T2">The type of the tuple's second component.</typeparam> 
    public class WTuple<T1, T2> : IStructuralEquatable, IStructuralComparable, IComparable, IWTuple 
    { 
     private T1 _item1; 
     private T2 _item2; 

     #region ImplementedInterfaces 
     Int32 IStructuralEquatable.GetHashCode(IEqualityComparer comparer) 
     { 
      return comparer.GetHashCode(_item1); 
     } 
     Boolean IStructuralEquatable.Equals(Object other, IEqualityComparer comparer) { 
      if (other == null) return false; 
      WTuple<T1, T2> objTuple = other as WTuple<T1, T2>;//Tuple<t1, t2=""> objTuple = other as Tuple<t1, t2="">; 
      if (objTuple == null) { 
       return false; 
      } 
      return comparer.Equals(_item1, objTuple._item1) && comparer.Equals(_item2, objTuple._item2); 
     } 
     Int32 IStructuralComparable.CompareTo(Object other, IComparer comparer) 
     { 
      if (other == null) return 1; 
      WTuple<T1, T2> objTuple = other as WTuple<T1, T2>;//Tuple<t1, t2=""> objTuple = other as Tuple<t1, t2="">; 
      if (objTuple == null) 
      { 
       throw new ArgumentException("ArgumentException_TupleIncorrectType", "other");//ArgumentException(Environment.GetResourceString("ArgumentException_TupleIncorrectType", this.GetType().ToString()), "other"); 
      } 
      int c = 0; 
      c = comparer.Compare(_item1, objTuple._item1); 
      if (c != 0) return c; 
      return comparer.Compare(_item2, objTuple._item2); 
     } 
     Int32 IComparable.CompareTo(Object obj) 
     { 
      return ((IStructuralComparable)this).CompareTo(obj, Comparer<object>.Default); 
     } 
     Int32 IWTuple.GetHashCode(IEqualityComparer comparer) 
     { 
      return ((IStructuralEquatable)this).GetHashCode(comparer); 
     } 
     string IWTuple.ToString(StringBuilder sb) 
     { 
      sb.Append(_item1); 
      sb.Append(", "); 
      sb.Append(_item2); 
      sb.Append(")"); 
      return sb.ToString(); 
     } 
     int IWTuple.Size 
     { 
      get { return 2; } 
     } 
     #endregion 

     #region WTuple 
     /// <summary> 
     /// Initializes a new instance of the System.WTuple&lt;T1,T2&gt; class. 
     /// </summary> 
     /// <param name="item1">The value of the tuple's first component.</param> 
     /// <param name="item2">The value of the tuple's second component.</param> 
     public WTuple(T1 item1, T2 item2) 
     { 
      _item1 = item1; 
      _item2 = item2; 
     } 
     /// <summary> 
     /// Gets or sets the value of the current System.WTuple&lt;T1,T2&gt; object's first component. 
     /// </summary> 
     public T1 Item1 
     { 
      get { return _item1; } 
      set { _item1 = value; } 
     } 
     /// <summary> 
     /// Gets or sets the value of the current System.WTuple&lt;T1,T2&gt; object's second component. 
     /// </summary> 
     public T2 Item2 
     { 
      get { return _item2; } 
      set { _item2 = value; } 
     } 
     /// <summary> 
     /// Returns a value that indicates whether the current System.WTuple&lt;T1,T2&gt; object 
     /// is equal to a specified object. 
     /// </summary> 
     /// <param name="obj">The object to compare with this instance.</param> 
     /// <returns>true if the current instance is equal to the specified object; otherwise, 
     /// false.</returns> 
     public override Boolean Equals(Object obj) 
     { 
      return ((IStructuralEquatable)this).Equals(obj, EqualityComparer<object>.Default); 
     } 
     /// <summary> 
     /// Returns the hash code for the current System.WTuple&lt;T1,T2&gt; object. 
     /// </summary> 
     /// <returns>A 32-bit signed integer hash code.</returns> 
     public override int GetHashCode() 
     { 
      return ((IStructuralEquatable)this).GetHashCode(EqualityComparer<object>.Default); 
     } 
     /// <summary> 
     /// Returns a string that represents the value of this System.WTuple&lt;T1,T2&gt; instance. 
     /// </summary> 
     /// <returns>The string representation of this System.WTuple&lt;T1,T2&gt; object.</returns> 
     public override string ToString() 
     { 
      StringBuilder sb = new StringBuilder(); 
      sb.Append("("); 
      return ((IWTuple)this).ToString(sb); 
     } 
     #endregion 
    } 
} 
+1

Este código no hace absolutamente nada que use la estructura de la que hereda, pero establece los valores subyacentes de Tuple una vez que el constructor ... donde permanecen invariables, e inmutables. El uso del 'nuevo operador en frente de las Propiedades es innecesario y no tiene efecto. Cambie el código en el colocador para 'Item1 a esto, y establezca el valor a veces de vista para ver que los valores en la base nunca cambian: establecer { _item1 = value; Console.WriteLine (_item1.ToString()); Console.WriteLine (base.Item1.ToString()); } – BillW

+0

Gracias por mencionar esto. Lo siento. En realidad, nunca probé las funciones anuladas, sino que solo usé Item1 y Item2 (lo que obviamente funciona). Descubrí que sería imposible de todos modos cambiar entradas en Tuple , debido a su uso de atributos de solo lectura, como vi aquí: http://reflector.webtropy.com/default.aspx/[email protected]/[email protected]/untmp/DEVDIV_TFS/Dev10/Releases/RTMRel/ndp/clr/src/BCL/System/Tuple @ cs/1305376/Tuple @ cs Sin embargo, actualicé el código, de modo que simplemente implementa las interfaces de forma similar a Tuple . – xamid

Cuestiones relacionadas