Skip to content

BRO1123: Use tuple syntax

(int, string) instead of ValueTuple<int, string>, and (1, "a") instead of new ValueTuple<int, string>(1, "a") or ValueTuple.Create(1, "a"). Replaces StyleCop SA1141.

Example

Before

using System;
using System.Collections.Generic;

public class Ranges
{
    public List<ValueTuple<int, int>> Spans { get; } = new List<ValueTuple<int, int>>();

    public ValueTuple<int, int> First() => ValueTuple.Create(0, 10);
}

After

using System;
using System.Collections.Generic;

public class Ranges
{
    public List<(int, int)> Spans { get; } = new List<(int, int)>();

    public (int, int) First() => (0, 10);
}

Why

Tuple syntax is shorter and the form the compiler and IDE show.

How the fix works

Types with 2 to 7 elements are rewritten wherever only a type can stand: declarations, type arguments, arrays, nullables, typeof, default, casts. Nested ones are done in one edit (ValueTuple<int, ValueTuple<int, int>> becomes (int, (int, int))). A creation becomes a tuple literal; a literal argument that the element type converts (new ValueTuple<long, string>(1, null)) gets a cast: ((long)1, (string)null).

Not reported

  • Creations with an argument that would name the element: ValueTuple.Create(x, y) would become (x, y), whose elements are named x and y; code reading t.Item1 would then be BRO1124's on the next run.
  • new ValueTuple<int, int>() (there's no tuple literal for it; StyleCop's fix writes (), which doesn't compile), creations with named arguments or an initializer, creations inside expression trees (they can't contain tuple literals), and arguments that would need a cast but aren't literals.
  • Types and creations with a comment inside (ValueTuple<int, /* id */ int>): the replacement would drop it.
  • ValueTuple<T> with one element, open generics (typeof(ValueTuple<,>)), more than 7 elements, using aliases.

Compared with StyleCop

StyleCop checks the types of declarations (fields, properties, methods, parameters, delegates, lambdas) and of creations, casts and default, but not locals, arrays, nullables, typeof or type arguments of calls; this rule checks every place where only a type can stand. Under dotnet format, StyleCop's fix doesn't run ("doesn't support Fix All in Solution"), so it leaves every tuple as it is.