2010-06-28 14 views
42

Je pensais utiliser la classe Tuple pour stocker 2 informations entières (StartAddress, EndAddress) dont j'ai besoin dans mon programme.Pourquoi les articles de Tuple sont ReadOnly?

Mais je découvre que Tuple éléments sont en lecture seule, donc si j'ai besoin de définir une valeur pour un élément, j'ai besoin de ré-instancier un Tuple.

Quelle est la raison de cette décision de conception?

+1

Je pense que dans la programmation OO, Tuple est habituellement juste une paresse de développeur pour décrire ses structures de données. Dans la programmation fonctionnelle, cependant, c'est le veau d'or. Je ne dis pas que ce soit bon ou mauvais et je suis aussi paresseux parfois. Juste qu'il peut y avoir des meilleures pratiques différentes à différents cas d'utilisation. – Rbjz

Répondre

41

Les tuples sont originaires de functional programming. En programmation (purement) fonctionnelle, tout est est immuable par conception - une certaine variable n'a qu'une seule définition à tout moment, comme en mathématiques. Les concepteurs .NET ont sagement suivi le même principe lors de l'intégration du style fonctionnel dans C#/.NET, bien qu'il soit finalement un langage impératif (hybride?).

Note: Bien que je soupçonne que le fait que les tuples soient immuables ne rende pas vraiment votre tâche beaucoup plus difficile, il y a aussi des types anonymes (ou peut-être juste une structure simple) que vous pourriez utiliser.

+9

Ce sont les concepteurs CLR, pas les concepteurs C#. System.Tuple dans .NET 4 sont aussi implicitement utilisés par F #. –

+4

C'était plus les développeurs BCL que les concepteurs C# - il y avait une décision, maintenant que F # rejoignait l'étable des langages .Net pour avoir un type Tuple unifié. –

+1

Ahh l'inévitable pédant. En outre, F # utilisait ses propres types de tuple avant .NET 4.0 - c'est en quelque sorte non pertinent de toute façon. – Noldorin

-1

Vous avez seulement les getters des propriétés ItemX, c'est vrai, mais j'ai trouvé un moyen d'instancier d'abord un tupple avec des valeurs vides et de les remplir après les mots.

Si vous faites quelque chose comme ceci:

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); 

Le tplTemp passé comme un paramètre de sortie aura ses 2 valeurs d'articles de la collection. Donc, c'est une façon de faire au cas où cela peut aider quelqu'un.

+2

Ce n'est pas un moyen de remplir un Tuple avec des valeurs. Tout ce que vous avez fait est de créer un second Tuple et d'assigner tplTemp à sa valeur. Vous code équivaut à faire juste: tplTemp = new Tuple ("some", "values"); – gerrard00

1

Je me demande pourquoi il n'y a pas une telle chose. Cependant, c'est ce que je préfère utiliser.

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

Ce code ne fait absolument rien qui utilise la structure dont il hérite mais définit les valeurs du Tuple sous-jacent une fois que le constructeur ... où elles restent invariantes et immuables. L'utilisation du nouvel opérateur devant les propriétés est inutile et n'a aucun effet. Modifiez le code dans le setter pour 'Item1 à ceci, et définissez la valeur d'une vue fois pour voir que les valeurs dans la base ne sont jamais changées: set { _item1 = valeur; Console.WriteLine (_item1.ToString()); Console.WriteLine (base.Item1.ToString()); } – BillW

+0

Merci de mentionner cela. Je suis désolé. En fait, je n'ai jamais testé les fonctions surchargées, mais seulement utilisé Item1 et Item2 (qui fonctionne évidemment). J'ai compris qu'il serait de toute façon impossible de changer les entrées dans Tuple , en raison de son utilisation des attributs readonly, comme je l'ai vu ici: http://reflector.webtropy.com/default.aspx/[email protected]/[email protected]/untmp/DEVDIV_TFS/Dev10/Releases/RTMRel/ndp/clr/src/BCL/Système/Tuple @ cs/1305376/Tuple @ cs Cependant, j'ai mis à jour le code, de sorte qu'il implémente juste les interfaces d'une manière similaire à Tuple . – xamid