How-To's

C# 7.0 and 7.1 support in ReSharper – Tuples

ReSharper support for C# 7 and C# 7.1ReSharper 2017.1 and 2017.2 bring better support for C# 7.0 and C# 7.1, with a number of new inspections, quick-fixes and context actions. In this 6th part of our blog series, let’s cover how ReSharper (and Rider) work with tuples and how they help with inferring tuple names (spec) in our code. Tuples have been around for a while, and keep evolving in both C# as well as in ReSharper’s features that you know and love.

In this series:

Tuples

Before, if we had a situation where we needed to pass around a few values (e.g. as a function return value or in a LINQ expression), we’d have to resort to the System.Tuple<T1, T2, ...> types. Tuples allow us to pass around values of any type using their properties Item1, Item2, …, without having to create a specialized object for those cases.

With C# 7.0 came language support for tuples and deconstruction. Instead of having to use these clunky objects (that are allocated on the managed heap and thus cause additional memory traffic), we can now use the ValueTuple type (which is a struct) using plain C# code:

// Before:
private Tuple<string, int> GetNameAndAge()
{
    return new Tuple<string, int>("Maarten", 33);
}

private void Example()
{
    var nameAndAge = GetNameAndAge();
    var name = nameAndAge.Item1;
    var age = nameAndAge.Item2;

    // ...
}

// After:
private (string, int) GetNameAndAge()
{
    return ("Maarten", 33);
}

private void Example()
{
    var (name, age) = GetNameAndAge();

    // ...
}

More concise, and better in terms of memory usage and allocations. Still, the properties of the tuple returned by GetNameAndAge() are named Item1 and Item2. We can do better, and use custom names by adding those in the GetNameAndAge() return type:
Naming tuple values

C# 7.1 adds another language feature on top: tuple projection initializers. This allows us to use tuples in projections (e.g. in LINQ), and have the language infer the property names for us. So instead of explicitly having to name our tuple values, they are inferred from the source object (in this case Person):

var person = list
    .Select(p => (p.Name, p.Age)) // instead of: .Select(p => (Name: p.Name, Age: p.Age))
    .FirstOrDefault(tuple => tuple.Age > 21);

Console.WriteLine(person.Name);
Console.WriteLine(person.Age);

ReSharper comes with an inspection and corresponding quick-fix that reveals redundant tuple value names when they can be inferred from initializer:
Tuple projection initializers in ReSharper

ReSharper comes with a number of other inspections. For example, it detects unused code and will let us use a quick-fix to, instead of assigning a variable, insert a “discard” (in the form of a _):
Detect unused variable in tuple and replace with discard

ReSharper can also detect typos in variable names when overriding a method or implementing an interface. A quick-fix can resolve the issue for us:
Detect typo in tuple component name using ReSharper quick-fix

Note if you want to use this language feature, the ValueTuple type is required. It’s built into .NET 4.7, .NET Core 2.0, Mono 5.0 and .NET Standard 2.0 – for other target frameworks make sure to install the System.ValueTuple package.

Download ReSharper Ultimate or check out Rider that takes advantage of ReSharper’s language support updates. We’d love to hear your thoughts.

image description