2010-06-28 9 views
42

Ich dachte daran, Tuple Klasse zu verwenden, um 2 ganzzahlige Informationen (StartAddress, EndAddress) zu speichern, die ich in meinem Programm brauche.Warum Tuple-Elemente ReadOnly?

Aber ich entdecke, dass Tuple Elemente ReadOnly sind, wenn ich also einen Wert für ein Element festlegen muss, muss ich ein Tuple erneut instanziieren.

Was ist der Grund für diese Designentscheidung?

+1

Ich denke in OO-Programmierung, ist Tuple in der Regel nur eine Entwickler Faulheit, seine Datenstrukturen zu beschreiben. In der funktionalen Programmierung ist es jedoch das goldene Kalb. Ich sage nicht, entweder ist gut oder schlecht und ich bin auch mal faul. Nur dass es verschiedene Best Practices für unterschiedliche Anwendungsfälle geben kann. – Rbjz

Antwort

41

Tupel entstanden in functional programming. In der (rein) funktionalen Programmierung ist alles von Entwurf her unveränderlich - eine bestimmte Variable hat immer nur eine einzige Definition, wie in der Mathematik. Die .NET-Designer folgten bei der Integration des funktionalen Stils in C# /. NET mit Bedacht dem gleichen Prinzip, obwohl sie letztendlich eine hauptsächlich zwingende (hybride?) Sprache war.

Hinweis: Obwohl ich die Tatsache, dass Tupel unveränderlich sind, nicht wirklich schwierig machen, gibt es auch anonyme Typen (oder vielleicht nur eine einfache Struktur), die Sie verwenden möchten.

+9

Es sind die CLR-Designer, nicht die C# -Designer. System.Tuple in .NET 4 wird auch implizit von F # verwendet. –

+4

Es waren eher die BCL-Entwickler als die C# -Designer - es gab eine Entscheidung, dass F # nun in den stabilen .Net-Sprachen aufgenommen wurde, um einen einheitlichen Tuple-Typ zu haben. –

+1

Ahh der unvermeidliche Pedant. Außerdem hat F # vor .NET 4.0 seine eigenen Tupeltypen verwendet - es ist irgendwie irrelevant. – Noldorin

-1

Sie haben nur die Getter der ItemX-Eigenschaften, das ist richtig, aber ich habe einen Weg gefunden, zuerst ein Tupple mit leeren Werten zu instanziieren und sie danach zu füllen.

Wenn Sie so etwas tun:

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

Die tplTemp als Out-Parameter übergeben wird es 2 Artikel Werte aus der Sammlung. Das ist also eine Möglichkeit, falls das jemand helfen kann.

+2

Dies ist keine Möglichkeit, ein Tupel mit Werten zu füllen. Alles, was Sie getan haben, ist ein zweites Tupel zu erstellen und tplTemp diesem Wert zuzuweisen. Ihr Code ist gleichbedeutend mit tu: tplTemp = new Tuple ("einige", "values"); – gerrard00

1

Ich frage mich, warum es so etwas nicht gibt. Es ist jedoch, was ich bevorzuge.

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

Dieser Code tut absolut nichts, das die Struktur verwendet, von der er erbt, sondern legt die zugrunde liegenden Tuple-Werte nach dem Konstruktor ... fest, wo sie invariant und unveränderbar bleiben. Die Verwendung des neuen Operators vor den Eigenschaften ist unnötig und hat keine Auswirkungen. Ändern Sie den Code in der Setter für 'Item1 zu diesem, und legen Sie den Wert eine Ansicht mal fest, um zu sehen, dass die Werte in der Basis nie geändert werden: set { _item1 = Wert; Console.WriteLine (_item1.ToString()); Console.WriteLine (base.Item1.ToString()); } – BillW

+0

Danke für die Erwähnung. Es tut mir Leid. Eigentlich habe ich die überschriebenen Funktionen nie getestet, sondern nur Item1 und Item2 benutzt (was natürlich funktioniert). Ich habe herausgefunden, dass es sowieso unmöglich wäre, Einträge in Tuple zu ändern, da Readonly-Attribute verwendet werden, wie ich hier gesehen habe: http://reflector.webtropy.com/default.aspx/[email protected]/[email protected]/unmp/DEVDIV_TFS/Dev10/Releases/RTMRel/ndp/clr/src/BCL/System/Tuple @ cs/1305376/Tuple @ cs Allerdings habe ich den Code aktualisiert, so dass es nur die Schnittstellen auf ähnliche Weise wie Tuple implementiert . – xamid