Do you have problems with C# Tuple class because items are read only?

While I was working on a small Windows Form tool in C#, which should help me to save and load parameters for a command line application, I run into the problem that not the complete textbox controls should be saved, but only the name and the text content. So, I had the requirement to save only a subset of the form fields. After thinking a while, I came to the idea to use Linq in combination with the Tuple class and I did some research about Tuples at all.

In mathematics, a finite sequence of elements is called a Tuple and they rise popularity with the implementation of functional programming languages. Like in mathematics, in functional programming a certain variable has a single value at all the time. So, Tuples are immutable or in other words “read only” by design and implementations like in C# are following this design.

Beside other usage of Tuples in programming languages, it’s commonly used to return a subset of data. Think about following use case: i.e. there is a list of territory definitions with fields like ZIP Code, City, Region, Population etc. and this list must be filtered and only a subset of the territory fields should be returned.

Here a code snippet for the above mentioned class definition:

// Define a class to store data
class Territory { public int zip; public string city; public string region; };

With Linq we could pretty easy do the filtering requirement, but we would have difficulties to return only a subset of the fields. Here a sample how it could be done:

// Define a sample list of objects to work with
Territory[] myTerritories = new Territory[] {
                                new Territory{zip=4153,city="Reinach",region="BL"},
                                new Territory{zip=8304,city="Wallisellen",region="ZH"},
                                new Territory{zip=3018,city="Bern",region="BE"}};

// Select a complete Territory subset variant 1
var subset1 = from Territory t in myTerritories
                   where t.region.StartsWith("B")
                         select t;
// Select a complete Territory subset variant 2
var subset2 = myTerritories.Where(t => t.region.StartsWith("B"));

So, here comes the usage of Tuples. To return only a subset of the territory fields, this fields must be stored in new instances of the Tuple class. The result will be a list of Tuples instead of a list of Territories.

Here you find a code snippet, returning a subset of the territory structure in a list of Tuples after the filtering:

// Select only a subset of territory fields as a list of Tuples
var subset3 = myTerritories.Where(t => t.region.StartsWith("B"))
                           .Select(t => new Tuple<int, string>(t.zip, t.city));

The problem is now, that Tuples are immutable / read only and follwing code would not compile:

subset3.ElementAt(0).Item2 = "Reinach BL";

So, the best solution is, to define a new class simillar to the Tuple class with a propper constructor and use this class instead of the Tuple class. Here the complete sample code:

class Program
{
    // Define a class to store data
    class Territory { public int zip; public string city; public string region; };

    static void Main(string[] args)
    {
        // Define a sample list of objects to work with
        Territory[] myTerritories = new Territory[] {
                                      new Territory{zip=4153,city="Reinach",region="BL"},
                                      new Territory{zip=8304,city="Wallisellen",region="ZH"},
                                      new Territory{zip=3018,city="Bern",region="BE"}};

        // Select a complete Territory subset variant 1
        var subset1 = from Territory t in myTerritories
                           where t.region.StartsWith("B")
                                 select t;
        // Select a complete Territory subset variant 2
        var subset2 = myTerritories.Where(t => t.region.StartsWith("B"));

        // Select only a subset of territory fields as a list of Tuples
        var subset3 = myTerritories.Where(t => t.region.StartsWith("B"))
                                   .Select(t => new Tuple<int, string>(t.zip, t.city));

        // because tuples are immutable/read only, these
        // will not compile and therefore it's commented out:
        /* subset3.ElementAt(0).Item2 = "Reinach BL"; */

        // Select only a subset of territory fields as a list of entities
        var subset4 = myTerritories.Where(t => t.region.StartsWith("B"))
                                   .Select(t => new Entity<int, string>(t.zip, t.city));

        // because Entity is mutable these will work:
        subset4.ElementAt(0).Item2 = "Reinach BL";
    }
}
public class Entity<T1, T2>
{
    public Entity(T1 t1, T2 t2)
    {
        Item1 = t1;
        Item2 = t2;
    }
    public T1 Item1 { get; set; }
    public T2 Item2 { get; set; }
}
public class Entity<T1, T2, T3>
{
    public Entity(T1 t1, T2 t2, T3 t3)
    {
        Item1 = t1;
        Item2 = t2;
        Item3 = t3;
    }
    public T1 Item1 { get; set; }
    public T2 Item2 { get; set; }
    public T3 Item3 { get; set; }
}

So, I hope you had fun and please leave a comment.

Original Post: https://www.redtoo.com/ch/blog/do-you-have-problems-with-c-tuple-class-because-items-are-read-only/