Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is Using .NET 4.0 Tuples in my C# Code a Poor Design Decision?

People also ask

Is it good to use tuple in C#?

Why should we use Tuples? You may want to use a tuple to represent a set of heterogeneous data and provide an easy way to access that data. You can also take advantage of a tuple to return multiple values from a method or even pass multiple values to a method.

What is .NET tuple?

The Tuple<T> class was introduced in . NET Framework 4.0. A tuple is a data structure that contains a sequence of elements of different data types. It can be used where you want to have a data structure to hold an object with properties, but you don't want to create a separate type for it.

What are tuples in C?

Tuples in C++ A tuple is an object that can hold a number of elements. The elements can be of different data types.

When would you use a tuple C#?

A tuple allows you to combine multiple values of possibly different types into a single object without having to create a custom class. This can be useful if you want to write a method that for example returns three related values but you don't want to create a new class. We can create a Tuple using the Create method.


Tuples are great if you control both creating and using them - you can maintain context, which is essential to understanding them.

On a public API, however, they are less effective. The consumer (not you) has to either guess or look up documentation, especially for things like Tuple<int, int>.

I would use them for private/internal members, but use result classes for public/protected members.

This answer also has some info.


The way I see it, a Tuple is a shortcut to writing a result class (I am sure there are other uses too).

There are indeed other valuable uses for Tuple<> - most of them involve abstracting away the semantics of a particular group of types that share a similar structure, and treating them simply as ordered set of values. In all cases, a benefit of tuples is that they avoid cluttering your namespace with data-only classes that expose properties but not methods.

Here's an example of a reasonable use for Tuple<>:

var opponents = new Tuple<Player,Player>( playerBob, playerSam );

In the above example we want to represent a pair of opponents, a tuple is a convenient way of pairing these instances without having to create a new class. Here's another example:

var pokerHand = Tuple.Create( card1, card2, card3, card4, card5 );

A poker hand can be thought of as just a set of cards - and tuple (may be) a reasonable way of expressing that concept.

setting aside the possibility that I am missing the point of Tuples, is the example with a Tuple a bad design choice?

Returning strongly typed Tuple<> instances as part of a public API for a public type is rarely a good idea. As you yourself recognize, tuples requires the parties involved (library author, library user) to agree ahead of time on the purpose and interpretation of the tuple types being used. It's challenging enough to create APIs that are intuitive and clear, using Tuple<> publicly only obscures the intent and behavior of the API.

Anonymous types are also a kind of tuple - however, they are strongly typed and allow you to specify clear, informative names for the properties belonging to the type. But anonymous types are difficult to use across different methods - they were primarily added to support technologies like LINQ where projections would produce types to which we wouldn't normally want to assign names. (Yes, I know that anonymous types with the same types and named properties are consolidated by the compiler).

My rule of thumb is: if you will return it from your public interface - make it a named type.

My other rule of thumb for using tuples is: name method arguments and localc variables of type Tuple<> as clearly as possible - make the name represent the meaning of the relationships between elements of the tuple. Think of my var opponents = ... example.

Here's an example of a real-world case where I've used Tuple<> to avoid declaring a data-only type for use only within my own assembly. The situation involves the fact that when using generic dictionaries containing anonymous types, it's becomes difficult to use the TryGetValue() method to find items in the dictionary because the method requires an out parameter which cannot be named:

public static class DictionaryExt 
{
    // helper method that allows compiler to provide type inference
    // when attempting to locate optionally existent items in a dictionary
    public static Tuple<TValue,bool> Find<TKey,TValue>( 
        this IDictionary<TKey,TValue> dict, TKey keyToFind ) 
    {
        TValue foundValue = default(TValue);
        bool wasFound = dict.TryGetValue( keyToFind, out foundValue );
        return Tuple.Create( foundValue, wasFound );
    }
}

public class Program
{
    public static void Main()
    {
        var people = new[] { new { LastName = "Smith", FirstName = "Joe" },
                             new { LastName = "Sanders", FirstName = "Bob" } };

        var peopleDict = people.ToDictionary( d => d.LastName );

        // ??? foundItem <= what type would you put here?
        // peopleDict.TryGetValue( "Smith", out ??? );

        // so instead, we use our Find() extension:
        var result = peopleDict.Find( "Smith" );
        if( result.First )
        {
            Console.WriteLine( result.Second );
        }
    }
}

P.S. There is another (simpler) way of getting around the issues arising from anonymous types in dictionaries, and that is to use the var keyword to let the compiler 'infer' the type for you. Here's that version:

var foundItem = peopleDict.FirstOrDefault().Value;
if( peopleDict.TryGetValue( "Smith", out foundItem ) )
{
   // use foundItem...
}

Tuples can be useful... but they can also be a pain later. If you have a method that returns Tuple<int,string,string,int> how do you know what those values are later. Were they ID, FirstName, LastName, Age or were they UnitNumber, Street, City, ZipCode.


Tuples are pretty underwhelming addition to the CLR from the perspective of a C# programmer. If you have a collection of items that varies in length, you don't need them to have unique static names at compile time.

But if you have a collection of constant length, this implies that the fixed of locations in the collection each have a specific pre-defined meaning. And it is always better to give them appropriate static names in that case, rather than having to remember the significance of Item1, Item2, etc.

Anonymous classes in C# already provide a superb solution to the most common private use of tuples, and they give meaningful names to the items, so they are actually superior in that sense. The only problem is that they can't leak out of named methods. I'd prefer to see that restriction lifted (perhaps only for private methods) than have specific support for tuples in C#:

private var GetDesserts()
{
    return _icecreams.Select(
        i => new { icecream = i, topping = new Topping(i) }
    );
}

public void Eat()
{
    foreach (var dessert in GetDesserts())
    {
        dessert.icecream.AddTopping(dessert.topping);
        dessert.Eat();
    }
}