如何迭代元组项目

时间:2017-04-11 08:56:59

标签: c# tuples ienumerable

如何迭代元组中的项目,当我在编译时不知道元组由哪些类型组成?我只需要一个IEnumerable对象(用于序列化)。

private static IEnumerable TupleToEnumerable(object tuple)
{
    Type t = tuple.GetType();
    if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Tuple<,>))
    {
        var x = tuple as Tuple<object, object>;
        yield return x.Item1;
        yield return x.Item2;
    }
}

4 个答案:

答案 0 :(得分:7)

您可以使用Type.GetProperties

进行反映来访问属性及其值
var values = tuple.GetType().GetProperties().Select(property => property.GetValue(tuple));

所以你的方法将是非常简单的Linq查询

private static IEnumerable TupleToEnumerable(object tuple)
{
    // You can check if type of tuple is actually Tuple
    return tuple.GetType()
                .GetProperties()
                .Select(property => property.GetValue(tuple));
}

答案 1 :(得分:3)

这里的一个问题是您必须处理多种Tuple类型:Tuple<T1, T2>Tuple<T1, T2, T3>等。(我假设您希望这与任意元组一起使用物品数量。)

这样做有点hacky,看看该类型的名称是否以System.Tuple开头:

public static IEnumerable TupleToEnumerable(object tuple)
{
    Type t = tuple.GetType();

    if (t.IsGenericType && t.GetGenericTypeDefinition().FullName.StartsWith("System.Tuple"))
    {
        for (int i = 1;; ++i)
        {
            var prop = t.GetProperty("Item" + i);

            if (prop == null)
                yield break;

            yield return prop.GetValue(tuple);
        }
    }
}

如果你不喜欢FullName.StartsWith(...)的hackyness,那么就可以让它变得更安全:

public static IEnumerable TupleToEnumerable(object tuple)
{
    Type t = tuple.GetType();

    if (isTupleType(t))
    {
        for (int i = 1;; ++i)
        {
            var prop = t.GetProperty("Item" + i);

            if (prop == null)
                yield break;

            yield return prop.GetValue(tuple);
        }
    }
}

private static bool isTupleType(Type type)
{
    if (!type.IsGenericType)
        return false;

    var def = type.GetGenericTypeDefinition();

    for (int i = 2;; ++i)
    {
        var tupleType = Type.GetType("System.Tuple`" + i);

        if (tupleType == null)
            return false;

        if (def == tupleType)
            return true;
    }
}

答案 2 :(得分:0)

您的代码无法按预期工作,因为您在使用Tuple时期望与Tuple<object,object>完全匹配,而不是这种情况

您可以尝试以下更通用的方法(如果您希望始终有两个项目)

 class Program
    {
        static void Main(string[] args)
        {
            Tuple<string, string> tuples = new Tuple<string, string>("test","test");
            foreach (string item in TupleToEnumerable<string>(tuples))
            {
                Console.WriteLine(item);   

            }
        }

        private static IEnumerable<T> TupleToEnumerable<T>(object tuple)
        {
            Type t = tuple.GetType();
            if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Tuple<,>))
            {
                var x = tuple as Tuple<T, T>;
                yield return x.Item1;
                yield return x.Item2;
            }
        }
    }

答案 3 :(得分:0)

在.NET Core 2.0+或.NET Framework 4.7.1+中,有

  • t.Length
  • t [i]

它来自ITuple interface界面

var data = (123, "abc", 0.983, DateTime.Now);
ITuple iT = data as ITuple;

for(int i=0; i<iT.Length;i++)
  Console.WriteLine(iT[i]);