Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Any tips to make working with Tuples easier in C#?

Tags:

c#

.net

tuples

Often you want to send multiple values but due to low use (i.e. it is only used in one or two places), it's hard to justify creating a new type.

The Tuple<...> and KeyValuePair<,> type are very useful, but there isn't real language support for them.

Well sort of, a nice trick to use for Lists of tuples is to create a type that extends the List and adding a custom add method: e.g.

public class TupleList<T1,T2> : List<Tuple<T1,T2>>{
    public void Add(T1 key, T2 value){
        base.Add(Tuple.Create(key, value));
    }
}

This means that if I have a method that takes an IEnumerable<Tuple<int,string>>, I can use the following code to quickly build up the list like so::

Foo(new TupleList<int,string>{{1,"one"},{2,"two"},{3,"three"}});

This makes winding values into a tuple list easier as we don't have to constantly keep saying Tuple.Create, and gets us almost to a nice functional languages syntax.

But when working with a tuple it is useful to unwind it out into its different components. This extension method might be useful in this respect::

    public static void Unwind<T1,T2>(this Tuple<T1,T2> tuple,out T1 var1,out T2 var2)
    {
        var1 = tuple.Item1;
        var2 = tuple.Item2;
    }

But even that's annoying as out parameters are not variant at all. That is if T1 is a string, I can't send in an object variable even though they are assignable, when as I can do the unwinding by hand otherwise. I can't really suggest a reason why you might want this variance, but if its there, I can't see why you would want to lose it.

Anyone have other tips to making working tuples, or tuple like objects easier in C#?

An important potential use for tuples might be generic memoization. Which is very easy in languages like F#, but hard in C#.

I'm currently using Tuples to supply a MethodBase and an array of tokens (constants, objects, or argument tokens), supplied to a dynamicly built object to construct certain member fields.

Since I wanted to make the syntax easier on API consumers, I created Add methods that can take a ConstructorInfo or a MethodInfo and a params array of objects.

Edit: Eric Lippert as usual has excellent motivation for using Tuples here and he even says what I suspected there really is no support: What requirement was the tuple designed to solve?

like image 934
Michael B Avatar asked Nov 24 '10 17:11

Michael B


1 Answers

In C# you can alias closed generic types, which Tuple is, this enables you to provide some better insight to what is intended. Doesn't change code much, but if you look at the example below the intent of what GetTemp is returning is better.

Without alias:

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            var result = GetTemp(10, 10);
            Console.WriteLine("Temp for {0} is {1}", result.Item2, result.Item1);
        }

        // You give a lat & a long and you get the closest city & temp for it
        static Tuple<double, string> GetTemp(double lat, double @long)
        {
            // just for example
            return Tuple.Create(10d, "Mordor");
        }        
    }
}

With alias:

namespace ConsoleApplication1
{
    using CityTemp = Tuple<double, string>;

    class Program
    {
        static void Main(string[] args)
        {
            var result = GetTemp(10, 10);
            Console.WriteLine("Temp for {0} is {1}", result.Item2, result.Item1);
        }

        // You give a lat & a long and you get the closest city & temp for it
        static CityTemp GetTemp(double lat, double @long)
        {
            // just for example            
            return new CityTemp(10, "Mordor");
        }
    }
}
like image 179
Robert MacLean Avatar answered Sep 27 '22 22:09

Robert MacLean