Developer Tips: C# Tuples

Our guest developer, Andrew Hinkle, gives us a taste of the new Tuples in C# 7.1 in today's post.

Last Updated: February 7th, 2018 • Develop •
grocery list

Tuples are simple data structures that store up to eight fields.

Those fields can consist of any types from strings and ints, to objects, and even other Tuples. When you find yourself adding "out" parameters to your methods or creating a simple POCO or model to return multiple fields, you should consider using a Tuple.

Use Tuples to simplify code and reduce the number of classes that need created. As of C# 7 named parameters and better performance have made them worthwhile using.

There are some limitations. Readable and maintainable code is important and many people prefer a well-defined model. As a rule of thumb if you are going to return more than three fields, review your method to determine if Tuples still make since or if a model makes the code easier to read. Using Tuples between MVC ViewModels and Views have a weird quirk. Read about all the Pros and Cons in the Resources links below.

The following are examples of how to use Tuples.

Let's start by reviewing the older styles to the latest and greatest.

These examples including some basic unit tests and are stored in my GitHub Tips repository.

Tuple Class

If you prefer new-ing up the Tuple object directly, here's the code:

public class UserRepositoryTupleClass
{
    public List<Tuple<string, string>> GetFirstNameAndLastNameList()
    {
        var users = new List<Tuple<string, string>>
        {
            new Tuple<string, string>("John", "Doe"),
            new Tuple<string, string>("Steve", "Smith")
        };

        return users;     }
    public Tuple<string, string> GetFirstNameAndLastName()     {         return new Tuple<string, string>("John", "Doe");     } }
// Example Usage: var repository = new UserRepositoryTupleClass(); var firstNameAndLastName = repository.GetFirstNameAndLastName();
// Tuple items are named Item1 and Item2. var firstName = firstNameAndLastName.Item1; var lastName = firstNameAndLastName.Item2;

Unnamed Tuples

Using parenthesis was the more common syntax for Tuples. Cleaner, except we still have that pesky Item1, Item2 usage. Notice that the example usage is identical to the Tuple class.

public class UserRepositoryUnnamedTuples
{
    public List<(string, string)> GetFirstNameAndLastNameList()
    {
        var users = new List<(string, string)>
        {
            ("John", "Doe"),
            ("Steve", "Smith")
        };

        return users;     }
    public (string, string) GetFirstNameAndLastName()     {         return ("John", "Doe");     } }

// Example Usage: var repository = new UserRepositoryUnnamedTuples(); var firstNameAndLastName = repository.GetFirstNameAndLastName(); // Tuple items are named Item1 and Item2. var firstName = firstNameAndLastName.Item1; var lastName = firstNameAndLastName.Item2;

Named Tuples

Named Tuples are AWESOME! As of C# 7, you could now give names to the fields in Tuples making them SO much more useful and self-documenting.

public class UserRepositoryNamedTuples
{
    public List<(string FirstName, string LastName)> GetFirstNameAndLastNameList()
    {
        var users = new List<(string FirstName, string LastName)>
        {
            ("John", "Doe"),
            ("Steve", "Smith")
        };

        return users;     }
    public (string FirstName, string LastName) GetFirstNameAndLastName()     {         return (FirstName: "John", LastName: "Doe");     } }

// Example Usage: var repository = new UserRepositoryNamedTuples(); var firstNameAndLastName = repository.GetFirstNameAndLastName();
// Tuple items are named. var firstName = firstNameAndLastName.FirstName; var lastName = firstNameAndLastName.LastName;

Nested Tuples

Nested Tuples follows the same syntax. Just don't go crazy deep or you might confuse your C# code for LISP.

public class UserRepositoryNestedTuples
{
    public List<(string FirstName, string LastName,
        (string City, string State) Address)> GetFirstNameAndLastNameList()
    {
        var users = new List<(string FirstName, string LastName,
            (string City, string State) Address)>
        {
            ("John", "Doe", ("Columbus", "OH")),
            ("Steve", "Smith", ("Lansing", "MI"))
        };

        return users;     }
    public (string FirstName, string LastName,         (string City, string State) Address) GetFirstNameAndLastName()     {         return (FirstName: "John", LastName: "Doe", Address: ("Columbus", "OH"));     } }
// Example Usage: var repository = new UserRepositoryNestedTuples(); var firstNameAndLastName = repository.GetFirstNameAndLastName();
// Nested Tuples var firstName = firstNameAndLastName.FirstName; var lastName = firstNameAndLastName.LastName; var city = firstNameAndLastName.Address.City; var state = firstNameAndLastName.Address.State;

Resources

  • Microsoft technical documentation on Tuples
  • Overview on the older, more explicit, way of doing tuples which explains the limitations on the number of fields supported in a Tuple [MSDN]
  • Great overview on how Tuples work especially in the IL. Joseph provides a great example with MVC ViewModels and the View. At compile time the named tuples are converted to the old style as Item1, Item2, etc., so while available they leave a horrible code smell. Read his article for more details on the Pros and Cons of Tuples.

Conclusion

In summary, if you have been holding out on using Tuples like me due to the lack of naming fields or performance issues before C# 7, it's time to give them another chance.

Have you used the new Tuples yet? Do you like the new way? Post your comments and let's discuss!

Picture of Andrew Hinkle

Andrew Hinkle has been developing applications since 2000 from LAMP to Full-Stack ASP.NET C# environments from manufacturing, e-commerce, to insurance.

He has a knack for breaking applications, fixing them, and then documenting it. He fancies himself as a mentor in training. His interests include coding, gaming, and writing. Mostly in that order.

comments powered by Disqus