A Tipple with a Tuple

One of the most controversial and questioned data types available to the C# developer is the “Tuple.” A data type (actually a class) in the System name space, the Tuple has been the subject of debate, discouragement, and downright humiliation since it first saw the light of day.

Why, though, would one data type cause so much pain for us humble developers? Well, it all lies with the fact of just what a Tuple is.

A Tuple, it happens, is kind of like a dynamic class that has a limited number of properties that are in strict order. In the case of .NET, it has an upper limit of 7.

As way of an example, let’s take a look at the following example, which comes straight from the MSDN documentation.

using System;

namespace Tuples
{
   class Program
   {
      static void Main()
      {

         var primes = Tuple.Create(2, 3, 5, 7, 11, 13, 17, 19);

          Console.WriteLine("Prime numbers less than 20: " +
            "{0}, {1}, {2}, {3}, {4}, {5}, {6}, and {7}",
            primes.Item1, primes.Item2, primes.Item3,
            primes.Item4, primes.Item5, primes.Item6,
            primes.Item7, primes.Rest.Item1);
      }
   }
   }

When this is compiled and run, you’ll get the following output:

Tuple
Figure 1: Listing of the prime numbers less than 20

Nothing complicated here, right?

Look closely at the source code, though. You’ll quickly see that the items added in the Tuple’s constructor are available via the properties ‘Item1‘ through ‘Item7‘ with anything further being available via the ‘Rest‘ property (more on that soon).

What we essentially have here is a class with seven named properties, that can be used everywhere you would use a normal class, in the same manner as a normal class.

It’s not beyond the realms of possibility to write an entire application using nothing but Tuples to represent your application objects. The reality, however, is that it would be an absolute maintenance nightmare if you did.

This very subject about using Tuples rather than correctly defined classes is one of the main reasons why Tuples have such a bad name and more than a fair few beginners have used them in such a way before they’ve learned how to do proper OOP-based class design when starting out in C#.

If Tuples are such a bad idea, why where they added to C# in the first place?

Well, it turns out there are a few cases where these things are genuinely useful. The first and probably most obvious case is in database record access. When reading ADO.NET data readers, you could, for instance, do the following:

DbCommand command = new SqlCommand("select * from foo",
   new SqlConnection());
using (DbDataReader reader = command.ExecuteReader())
{
   reader.Read();
   var dbRecord = Tuple.Create(reader[0], reader[1],
                  reader[2], reader[3]);
   }

Allowing you to then access that record as:

Console.WriteLine(dbRecord.Item1);
Console.WriteLine(dbRecord.Item2);
Console.WriteLine(dbRecord.Item3);
Console.WriteLine(dbRecord.Item4);

This might come in handy for very simple scenarios or in cases where you don’t know the actual output of the database record you’re retrieving.

In a similar vein, you may find it useful to provide a level of generic access to unknown data sources.

I myself have used this approach with communications software when dealing with binary SMS text messages.

However, one place I found it very, very useful recently was in a Web application I was developing. As many of my regular readers may know, I’m a big fan of Nancy, and I’ve even written a book on it; it’s available in the Syncfusion free eBook series.

One of the great things I like about Nancy is the ease with which you can return JSON-formatted data to your Web-based user interface. It’s as simple as this:

private dynamic Index(dynamic paramaters)
{
   return Response.AsJson(new {Foo = 1, Bar = "Hello"});
}

This will result in your AJAX call receiving the following:

{ "Foo":1, "Bar": "Hello" }

Directly in a format that JavaScript natively understands.

Generally, however, you only have one object available to return or a specifically defined set; for example:

private dynamic Index(dynamic paramaters)
{
   PageTitle title = new PageTitle
   {
      MainTitle = "Foo",
      SubTitle = "Bar"
   };
   return Response.AsJson(title);
}

You can’t, however, return multiple objects, unless you combine them into a higher level object; for example:

      private dynamic Index(dynamic paramaters)
      {
         PageTitle title = new PageTitle
         {
            MainTitle = "Foo",
            SubTitle = "Bar"
         };

         PageTitle title2 = new PageTitle
         {
            MainTitle = "Foo2",
            SubTitle = "Bar2"
         };

         Combiner combiner = new Combiner
         {
            Title1 = title,
            Title2 = title2
         };

         return Response.AsJson(combiner);
      }


   }

   public class Combiner
   {
      public PageTitle Title1 { get; set; }
      public PageTitle Title2 { get; set; }
   }

As you can see, the code is starting to get a bit long here.

Fear not, though, because this is exactly where the Tuple excels. We now can rewrite our previous Nancy handler as follows:

   private dynamic Index(dynamic paramaters)
   {
      var combiner = Tuple.Create(
         new PageTitle
         {
            MainTitle = "Foo",
            SubTitle = "Bar"
         },

         new PageTitle
         {
            MainTitle = "Foo2",
            SubTitle = "Bar2"
         });

         return Response.AsJson(combiner);
      }

The best part about this is that each item can be ANY type of object, not just the classes here that I’ve used as an example.

In the first combiner, your two class types could only ever be ‘PageTitle’ type objects. By using a Tuple, you can assign and re-assign in a very dynamic fashion, and ALL without using dynamic language typing, casting, or generics.

Tuples, at the end of the day, are like any tool in your C# toolbox. They’re there for the circumstances that need them, and can be safely stowed away when you don’t.

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read