Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert ValueTuple to IEnumerable

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);
    }
  }
}
like image 427
William Jockusch Avatar asked May 16 '17 16:05

William Jockusch


2 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) );
}
like image 109
NoonKnight Avatar answered Sep 17 '22 07:09

NoonKnight


One way to do this is via the ITuple interface.

public interface ITuple
{
    int Length { get; }
    object this[int index] { get; }
}

It is only available in .NET Core 2.0, Mono 5.0 and the next version of .NET Framework (unreleased, following 4.7). It is not (and will never be) available as an add-on to older frameworks via the ValueTuple package.

This API is designed for usage by the C# compiler for future work on patterns.

like image 33
Julien Couvreur Avatar answered Sep 18 '22 07:09

Julien Couvreur