var Matt = new Hero();

C#, ASP.NET MVC, MEF, Javascript…and anything else that interests me.

Matthew Abbott On January - 5 - 2010

.NET 4.0 introduces a new type, the Tuple. In mathematics, a tuple is an ordered set of elements, e.g. (1, 2, 3, 4, 5) is a 5-tuple. In programming (i.e. type theory) a tuple has a fixed size and the underlying type of its components is explicit.

With this in mind, we can understand tuples simply as a wrapper type of two or more values, e.g.:

  var person = new Tuple<string, int>("Matt", 25);
  // person.Item1 ...
  // person.Item2

Whilst we wait for .NET 4.0 to come a’knocking, we can still capture this functionality with v2.0 of the framework, thanks to generics. We can define our own Tuple types, for instance:

namespace MyTuples
{
    using System;
    using System.Globalization;

    /// <summary>
    /// Represents a finite 2-item tuple.
    /// </summary>
    /// <typeparam name="TFirst">The type of the first item.</typeparam>
    /// <typeparam name="TSecond">The type of the second item.</typeparam>
    public class Tuple<TFirst, TSecond> : IEquatable<Tuple<TFirst, TSecond>>
    {
        #region Constructors
        /// <summary>
        /// Initialises a new instance of <see cref="Tuple{TFirst,TSecond}" />.
        /// </summary>
        public Tuple() { }

        /// <summary>
        /// Initialises a new instance of <see cref="Tuple{TFirst,TSecond}" />.
        /// </summary>
        /// <param name="first">The first item.</param>
        public Tuple(TFirst first)
        {
            this.First = first;
        }

        /// <summary>
        /// Initialises a new instance of <see cref="Tuple{TFirst,TSecond}" />.
        /// </summary>
        /// <param name="first">The first item.</param>
        /// <param name="second">The second item.</param>
        public Tuple(TFirst first, TSecond second)
        {
            this.First = first;
            this.Second = second;
        }
        #endregion

        #region Properties
        /// <summary>
        /// Gets or sets the first item.
        /// </summary>
        public TFirst First { get; set; }

        /// <summary>
        /// Gets or sets the second item.
        /// </summary>
        public TSecond Second { get; set; }
        #endregion

        #region Methods

        /// <summary>
        /// Calculates the hash code for this tuple.
        /// </summary>
        /// <returns>The hash code for this tuple.</returns>
        private int CalculateHashCode()
        {
            int hashCode = 0;

            TFirst first = default(TFirst);
            TSecond second = default(TSecond);

            if (!object.Equals(this.First, first)) {
                hashCode += this.First.GetHashCode();
            }

            if (!object.Equals(this.Second, second)) {
                hashCode += this.Second.GetHashCode();
            }

            return hashCode;
        }

        /// <summary>
        /// Gets the hash code for this tuple.
        /// </summary>
        /// <returns>The hash code for this tuple.</returns>
        public override int GetHashCode()
        {
            return CalculateHashCode();
        }

        /// <summary>
        /// Determines if this instance equals the specified tuple.
        /// </summary>
        /// <param name="other">The other tuple to compare to.</param>
        /// <returns>True if this instance equals the specified tuple, otherwise false.</returns>
        public bool Equals(Tuple<TFirst, TSecond> other)
        {
            if (other == null) {
                return false;
            }

            return (this.GetHashCode() == other.GetHashCode());
        }

        /// <summary>
        /// Determines if the two instances equal.
        /// </summary>
        /// <param name="firstTuple">The first tuple to compare.</param>
        /// <param name="secondTuple">The second tuple to compare.</param>
        /// <returns>True if the two instances are equal, otherwise false.</returns>
        public static bool Equals(Tuple<TFirst, TSecond> firstTuple, Tuple<TFirst, TSecond> secondTuple)
        {
            if (firstTuple == null && secondTuple == null) {
                return true;
            }

            if (firstTuple == null || secondTuple == null) {
                return false;
            }

            return firstTuple.Equals(secondTuple);
        }

        /// <summary>
        /// Determines if this instance equals the specified object.
        /// </summary>
        /// <param name="obj">The other object to compare to.</param>
        /// <returns>True if this instance equals the specified object, otherwise false.</returns>
        public override bool Equals(object obj)
        {
            if (obj == null) {
                return false;
            }

            if (obj is Tuple<TFirst, TSecond>) {
                return Equals(obj as Tuple<TFirst, TSecond>);
            }

            Type first = typeof(Tuple<TFirst, TSecond>);
            Type second = obj.GetType();

            throw new NotSupportedException(
                string.Format(CultureInfo.CurrentUICulture,
                              "Cannot check for equality between types '{0}' and '{1}'.",
                              first.Name,
                              second.Name));
        }
        #endregion
    }
}

But where would this be any use? We’ve all seen this before:

public Result DoSomething() {
  return new Result
  {
    Name = "Matt",
    Age = 25
  };
}

…and perhaps the even more face aching:

public void DoSomething(out string name, out int age) {
  name = "Matt";
  age = 25;
}

Often is the case when you have a function that you want to return multiple values, you resort to either one of the methods described above. This often results in your class library expanding rapidly due to the large number of these wrapper types who’s only purpose is to contain other types.

We could in fact solve this issue using a Tuple:

public Tuple<string, int> DoSomething() {
  return new Tuple<string, int>("Matt", 25);
}

Now, you could go one step further…how about an extension method that joins enumerations of types into Tuples?

namespace MyTuples
{
    using System;
    using System.Collections.Generic;
    using System.Linq;

    static class IEnumerableExtensions
    {
        #region Methods
        /// <summary>
        /// Converts the given enumerations to 2-part tuples.
        /// </summary>
        /// <typeparam name="TFirst">The type of the first item in the tuple.</typeparam>
        /// <typeparam name="TSecond">The type of the second item in the tuple.</typeparam>
        /// <param name="items">The first set of items.</param>
        /// <param name="secondItems">The second set of items.</param>
        /// <param name="includeUnmatched">Should we include unmatched items?</param>
        /// <returns>An enumeration of 2-part tuples created from the given sets.</returns>
        public static IEnumerable<Tuple<TFirst, TSecond>> ToTuples<TFirst, TSecond>(
            this IEnumerable<TFirst> items,
            IEnumerable<TSecond> secondItems, bool includeUnmatched)
        {
            if (items == null) {
                throw new ArgumentNullException("items");
            }

            if (secondItems == null) {
                throw new ArgumentNullException("secondItems");
            }

            TFirst[] firstArray = items.ToArray();
            TSecond[] secondArray = secondItems.ToArray();
            IList<Tuple<TFirst, TSecond>> results = new List<Tuple<TFirst, TSecond>>();

            int i = 0;

            for (; i < firstArray.Length; i++) {
                if (i < secondArray.Length) {
                    results.Add(new Tuple<TFirst, TSecond>(firstArray[i], secondArray[i]));
                } else if (includeUnmatched) {
                    results.Add(new Tuple<TFirst, TSecond>(firstArray[i], default(TSecond)));
                }
            }

            if (includeUnmatched && (i < secondArray.Length)) {
                for (; i < secondArray.Length; i++) {
                    results.Add(new Tuple<TFirst, TSecond>(default(TFirst), secondArray[i]));
                }
            }

            return results;
        }

        /// <summary>
        /// Converts the given enumerations to 2-part tuples.
        /// </summary>
        /// <typeparam name="TFirst">The type of the first item in the tuple.</typeparam>
        /// <typeparam name="TSecond">The type of the second item in the tuple.</typeparam>
        /// <param name="items">The first set of items.</param>
        /// <param name="secondItems">The second set of items.</param>
        /// <returns>An enumeration of 2-part tuples created from the given sets.</returns>
        public static IEnumerable<Tuple<TFirst, TSecond>> ToTuples<TFirst, TSecond>(
            this IEnumerable<TFirst> items,
            IEnumerable<TSecond> secondItems)
        {
            return ToTuples(items, secondItems, false);
        }
        #endregion
    }
}

What these methods allow us to do is create Tuples from each of the items. These examples are only using 2-tuple instances, but you can create Tuples and extension methods for however many types you want to wrap.

Given the above code, I could then do something like this:

string[] names = { "Matt", "Andy", "Chris" };
int[] ages = { 25, 30, 28 };

var people = names.ToTuples(ages);
foreach (var person in people)
{
    Console.WriteLine("Name: {0}, Age: {1}", person.First, person.Second);
}

Thanks to type inference, we don’t need to explictly state the types of the items in the tuples, the compiler will handle this for us. Nicey nicey eh?

Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Shout it
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter
Google Buzz (aka. Google Reader)
Categories: .NET, Development

Leave a Reply

You must be logged in to post a comment.

Me

Featured Posts

The Magic of IoC

I was bored…
…so I decided to design an IoC Container! This actually turned out to be a lot of fun too. I’d like to firstly state that a) there is no reason for this code, and b) this is not a replacement for established IoC solutions, such as Unity, Castle Windsor, Ninject, Authofac, StructureMap, and [...]

Integrating Regula with ASP.NET MVC and DataAnnotations

Previously I discovered Regula, an annotation-based validation framework used for client-side validation of form elements. I wondered if it was possible to automatically wire up client-side validation using DataAnnotation’s ValidationAttributes on the server side, very similar to how xVal might handle it.
This is by no means usable, its really an experiment to see what [...]

Regula as a jQuery Plugin

Earlier this evening I came across a Stack Overflow question regarding a most excellent new javascript validation framework, called Regula. Regula is an annotation-based validation framework that hides the complexities of binding complex validation events to controls by extending the DOM element itself with annotations about how it should be validated. Here is a [...]

Modular ASP.NET MVC using the Managed Extensibility Framework (MEF), Part Three

See also: Modular ASP.NET MVC using the Managed Extensibility Framework (MEF), Part One
See also: Modular ASP.NET MVC using the Managed Extensibility Framework (MEF), Part Two
Currently reading: Modular ASP.NET MVC using the Managed Extensibility Framework (MEF), Part Three

Firstly, sorry it’s been so long since my last MVC+MEF post, been a bit busy with life in general. [...]

Javascript Linq Extensions

I love Linq. Linq just makes code awesome. Well, that’s my view on it anyway. I also like Javascript, and through libraries like JQuery we’ve now got a framework whereby you can pretty much do anything, but often I like getting down to the bare-bones of Javascript and just having a go at what [...]

Search my site

Twitter Updates

Links