Convert ValueTuple to IEnumerable

2019-06-16 03:14发布

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);
    }
  }
}

2条回答
我欲成王,谁敢阻挡
2楼-- · 2019-06-16 03:53

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.

查看更多
贪生不怕死
3楼-- · 2019-06-16 04:07

A bit of reflection:

namespace ConsoleApp1
{
    using System;
    using System.Collections.Generic;
    using System.Linq;

    public class Program
    {
        public static void Main()
        {
            var tuple = (1, 2, 3, 4, 5, 6, 7);
            var items = ToEnumerable(tuple);

            foreach (var item in items)
            {
                Console.WriteLine(item);
            }
        }

        private static IEnumerable<object> ToEnumerable(object tuple)
        {
            if (tuple.GetType().GetInterface("ITupleInternal") != null)
            {
                foreach (var prop in tuple.GetType()
                    .GetFields()
                    .Where(x => x.Name.StartsWith("Item")))
                {
                    yield return prop.GetValue(tuple);
                }
            }
            else
            {
                throw new ArgumentException("Not a tuple!");
            }
        }
    }
}
查看更多
登录 后发表回答