Convert ValueTuple to IEnumerable

Viewed 3232

Is there a saner way to do the following:

public static class ValueTupleAdditions {
  public static IEnumerable<object> ToEnumerable<A, B>(this ValueTuple<A, B> tuple) {
    yield return tuple.Item1;
    yield return tuple.Item2;
  }
  public static IEnumerable<object> ToEnumerable<A, B, C>(this ValueTuple<A, B, C> tuple) {
    yield return tuple.Item1;
    yield return tuple.Item2;
    yield return tuple.Item3;
  }

  [etc]
}

EDIT: Since people are asking for a use case, here you go.

using Xunit;

namespace Whatever {

  public class SomeTestClass {
    public static IEnumerable<(string, Expression<Func<string, string>>, string)> RawTestData() {
      yield return ("Hello", str => str.Substring(3), "lo");
      yield return ("World", str => str.Substring(0, 4), "worl");
    }
    public static IEnumerable<object[]> StringTestData() {
      return RawTestData().Select(vt => new object[] { vt.Item1, vt.Item2, vt.Item3 });
       // would prefer to call RawTestData().Select(vt => vt.ToArray()) here, but it doesn't exist.
    }

    [Theory, MemberData(nameof(StringTestData))]
    public void RunStringTest(string input, Expression<Func<string, string>> func, string expectedOutput) {
      var output = func.Compile()(input);
      Assert.Equal(expectedOutput, output);
    }
  }
}
3 Answers

One way is to use an extension method based on ITuple, see also answer by Julien Couvreur:

public static IEnumerable<T> ToEnumerable<T>( this ITuple tuple ) {
    for ( var n = 0; n < tuple.Length; n++ ) yield return (T)tuple[ n ];
}

sample usage:

var directions = (
    right: (cx: 1, cy: 0),
    down: (cx: 0, cy: 1),
    left: (cx: -1, cy: 0),
    up: (cx: 0, cy: -1)
);
foreach ( var direction in directions.ToEnumerable<(int cx, int cy)>() ) {
    var (cx, cy) = direction;
    TryMovePiece( (x + cx, y + cy) );
}
Related