10

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?

Community
  • 1
  • 1
Michael B
  • 7,512
  • 3
  • 31
  • 57
  • Can you show us your use-case where you find it preferable to pass in parameters of type `object` rather than variables typed to what they should actually be? i.e. Show us how you'd like to be calling `Unwind` with a little bit of context. – Kirk Woll Nov 24 '10 at 17:37
  • 1
    out parameters are rigid, which is why they are not suggested as the go to choice. I'd kill for API support like F# has which turns out parameters into tuples. – Michael B Nov 24 '10 at 18:49
  • Composition over inheritance! – Eric Nov 24 '10 at 19:34
  • I don't quite follow, I don't think extension methods named Add are considered in the constructor syntax. If they are that is awesome. – Michael B Nov 24 '10 at 20:29
  • Couldnt you just use a Dictionary instead of what youre trying to do? – Nobody Nov 25 '10 at 15:51
  • A dictionary only works for pairs. If you want to for a triple, there is no built in container. – Michael B Nov 25 '10 at 17:36

3 Answers3

5

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");
        }
    }
}
Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92
Robert MacLean
  • 38,975
  • 25
  • 98
  • 152
4

Use Mono! They have experimental support for binding variables to tuple members so you could call a method like

Tuple<string, string, string, int, string> ParseUri (string url);

using code like

(user, password, host, port, path) = ParseUri (url);
Samuel Jack
  • 32,712
  • 16
  • 118
  • 155
2

There will be an awesome tuple feature coming with c#7 / visual studio 15.

basically you can do soething like that

static (int x, int y) DoSomething()
{
    return (1, 2);
}

static void Test()
{
    var cool = DoSomething();
    var value = cool.x;
}

Read according post

gsharp
  • 27,557
  • 22
  • 88
  • 134