59

Is there a class existing in .NET Framework 3.5 that would be equivalent to the .NET 4 Tuple?

I would like to use it in order to return several values from a method, rather than create a struct.

Mark Hurd
  • 10,175
  • 10
  • 62
  • 96
Otiel
  • 17,292
  • 13
  • 70
  • 120

6 Answers6

81

No, not in .Net 3.5. But it shouldn't be that hard to create your own.

public class Tuple<T1, T2>
{
    public T1 First { get; private set; }
    public T2 Second { get; private set; }
    internal Tuple(T1 first, T2 second)
    {
        First = first;
        Second = second;
    }
}

public static class Tuple
{
    public static Tuple<T1, T2> New<T1, T2>(T1 first, T2 second)
    {
        var tuple = new Tuple<T1, T2>(first, second);
        return tuple;
    }
}

UPDATE: Moved the static stuff to a static class to allow for type inference. With the update you can write stuff like var tuple = Tuple.New(5, "hello"); and it will fix the types for you implicitly.

Tomas Jansson
  • 20,796
  • 9
  • 68
  • 121
  • it doesn't have to be more involved, it depends on your business needs. The question says: "I would like to use it in order to return several values from a method, rather than create a struct." and you don't need comparison and equality for that. – Tomas Jansson Aug 19 '11 at 11:40
  • One, you haven't provided Equals implementation which .NET 4.0 tuples give you, two, you're talking about type inference not implicit conversion in the last case. – nawfal Jan 13 '14 at 01:24
  • @nawfal, thank you regarding the type inference. Regarding the equals implementation you can need my comment. That might not be needed depending on the business needs and I answered the specific questions and did not write a complete implementation as it is implemented in .NET 4.0. Also, I didn't say that this was a complete implementation of tuples. – Tomas Jansson Jan 13 '14 at 10:23
  • 1
    Hmmm. The q is about .NET 4.0 tuple equivalent. Not to nitpick, but equatability of tuples is something beginners usually overlook. That one aspect is actually worth mentioning. – nawfal Jan 13 '14 at 11:01
  • @nawfal, reading the whole question: "I would like to use it in order to return several values from a method, rather than create a struct." He doesn't mention anything about equality between tuples and if that's an issue it's not that hard to add. But again, you are totally right about the inference part and I have updated the answer. – Tomas Jansson Jan 13 '14 at 15:06
  • since Tuples are regarded values (hence the private setters), shouldn't this be rather a struct than a class? – matthias_buehlmann Mar 21 '14 at 17:53
  • 1
    FYI, the `Tuple` class appears to have changed in .NET 4.5; the properties arecalled `Item1` and `Item2` instead of `First` and `Second`. – ashes999 Sep 10 '14 at 19:12
  • For complete, and well-maintained, solutions see [answer with link to Mono](http://stackoverflow.com/a/25664056/199364) and [answer with link to NetLegacySupport](http://stackoverflow.com/a/33930399/199364) – ToolmakerSteve Apr 15 '17 at 20:43
26

I'm using this in my pre-4 projects:

public class Tuple<T1>  
{ 
    public Tuple(T1 item1) 
    { 
        Item1 = item1; 
    }   

    public T1 Item1 { get; set; }  
} 

public class Tuple<T1, T2> : Tuple<T1>  
{ 
    public Tuple(T1 item1, T2 item2) : base(item1) 
    { 
        Item2 = item2; 
    } 

    public T2 Item2 { get; set; }  
} 

public class Tuple<T1, T2, T3> : Tuple<T1, T2>  
{ 
    public Tuple(T1 item1, T2 item2, T3 item3) : base(item1, item2) 
    { 
        Item3 = item3; 
    } 

    public T3 Item3 { get; set; }  
} 

public static class Tuple  
{ 
    public static Tuple<T1> Create<T1>(T1 item1) 
    { 
        return new Tuple<T1>(item1); 
    } 

    public static Tuple<T1, T2> Create<T1, T2>(T1 item1, T2 item2) 
    { 
        return new Tuple<T1, T2>(item1, item2); 
    } 

    public static Tuple<T1, T2, T3> Create<T1, T2, T3>(T1 item1, T2 item2, T3 item3) 
    { 
        return new Tuple<T1, T2, T3>(item1, item2, item3); 
    }  
}
Hrvoje Hudo
  • 8,864
  • 5
  • 27
  • 41
24

In the event that you need them to have feature-parity with .Net 4.0 (primarily comparisson):

static class Tuple
{
    public static Tuple<T1, T2> Create<T1, T2>(T1 item1, T2 item2)
    {
        return new Tuple<T1, T2>(item1, item2);
    }
}

[DebuggerDisplay("Item1={Item1};Item2={Item2}")]
class Tuple<T1, T2> : IFormattable
{
    public T1 Item1 { get; private set; }
    public T2 Item2 { get; private set; }

    public Tuple(T1 item1, T2 item2)
    {
        Item1 = item1;
        Item2 = item2;
    }

    #region Optional - If you need to use in dictionaries or check equality
    private static readonly IEqualityComparer<T1> Item1Comparer = EqualityComparer<T1>.Default;
    private static readonly IEqualityComparer<T2> Item2Comparer = EqualityComparer<T2>.Default;

    public override int GetHashCode()
    {
        var hc = 0;
        if (!object.ReferenceEquals(Item1, null))
            hc = Item1Comparer.GetHashCode(Item1);
        if (!object.ReferenceEquals(Item2, null))
            hc = (hc << 3) ^ Item2Comparer.GetHashCode(Item2);
        return hc;
    }
    public override bool Equals(object obj)
    {
        var other = obj as Tuple<T1, T2>;
        if (object.ReferenceEquals(other, null))
            return false;
        else
            return Item1Comparer.Equals(Item1, other.Item1) && Item2Comparer.Equals(Item2, other.Item2);
    }
    #endregion

    #region Optional - If you need to do string-based formatting
    public override string ToString() { return ToString(null, CultureInfo.CurrentCulture); }
    public string ToString(string format, IFormatProvider formatProvider)
    {
        return string.Format(formatProvider, format ?? "{0},{1}", Item1, Item2);
    }
    #endregion
}
Jonathan Dickinson
  • 8,512
  • 1
  • 29
  • 58
  • Nice answer. This is what i was looking for (i'm on a project where i'm stuck at 3.5). Question : your `GetHashCode()` implementation is `(h1 << 3) ^ h2` while MS one (trought ILSpy) is `(h1 << 5) + h1 ^ h2`. does it really make a difference (performance wise) ? – tigrou May 15 '13 at 13:51
  • @tigrou XOR *should* be ever so slightly faster in terms the amount of silicon that get used to do it (it's still one CPU instruction though). That is seriously overdoing micro-optimization though - feel free to use whichever you see fit. – Jonathan Dickinson May 15 '13 at 14:41
  • I was thinking about possible collisions rather than time taken by to compute a hash code. – tigrou May 16 '13 at 11:52
  • @tigrou I guess the only way would be to test it. – Jonathan Dickinson May 19 '13 at 22:47
  • This is quite good, avoids boxing (which even the .NET implementation doesn't do). A small suggestion, you dont need the null check in your hash code function, the comparer does it for you. – nawfal Jan 13 '14 at 01:26
  • Brilliant. 'nuff said. – david.pfx Apr 04 '17 at 11:51
6

You can install NetLegacySupport.Tuple via nuget. This is the Tuple class from .Net 4.5 backported to .Net 2.0 and 3.5.

You can install this via the package manager in Visual Studio or using nuget on the commandline.

Here is the nuget package:

https://www.nuget.org/packages/NetLegacySupport.Tuple

Ashley Davis
  • 9,255
  • 7
  • 58
  • 79
2

Yes, there is a class called System.Collections.Generic.KeyValuePair that does the same thing (since .NET 2.0 I think).

http://msdn.microsoft.com/en-us/library/5tbh8a42.aspx

Ricky Helgesson
  • 3,576
  • 2
  • 19
  • 23
  • Yup, but that is not that useful if you want to return more than two values. Although you could nest `KeyValuePairs` within other `KeyValuePairs` for a quick fix. – yu_ominae Sep 02 '13 at 01:45
  • 3
    However, if what you have is not "a key and a value", it makes more sense to create your own custom structs or classes, or define some Tuple classes, like other answers. Poor practice to use a structure that implies you have "a key and a value", when you don't. Please avoid misleading people who have to read your code later! – ToolmakerSteve Dec 09 '13 at 22:13
  • Apologies for the downvote, as some people may consider this a useful work-around (though per my above comment, I consider this misleading), but more recent answers that give links to complete tuple implementations in mono and nuget should be higher than this answer. – ToolmakerSteve Apr 15 '17 at 20:39
2

Yes, you can just use Tuple.cs from mono:

You require the dependencies as well:
Tuples.cs
IStructuralComparable.cs
IStructuralEquatable.cs

You just put a

#define NET_4_0

in front of every

#if NET_4_0

and there you go, a feature-complete implementation of System.Tuple for .NET 2.0.

Stefan Steiger
  • 68,404
  • 63
  • 337
  • 408