【问题标题】:how to iterate over tuple items如何迭代元组项
【发布时间】:2017-04-11 08:56:59
【问题描述】:

当我在编译时不知道元组由哪些类型组成时,如何迭代元组中的项目?我只需要一个 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;
    }
}

【问题讨论】:

  • var values = tuple.GetType().GetProperties().Select(property =&gt; property.GetValue(tuple))

标签: c# tuples ienumerable


【解决方案1】:

您可以使用Type.GetProperties 反射访问属性及其值

var values = tuple.GetType().GetProperties().Select(p => p.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));
}

【讨论】:

    【解决方案2】:

    这里的一个问题是您必须处理多个Tuple 类型:Tuple&lt;T1, T2&gt;Tuple&lt;T1, T2, T3&gt; 等(我假设您希望它可以处理具有任意数量项目的元组。)

    一种有点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;
        }
    }
    

    【讨论】:

      【解决方案3】:

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

      • t.长度
      • 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]);
      

      【讨论】:

        【解决方案4】:

        您的代码无法按预期工作,因为当您使用 as Tuple 时,您期望 Tuple&lt;object,object&gt; 完全匹配,但事实并非如此

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

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

        【讨论】:

        • TupleToEnumerable<_string_>(tuples) - 不能像这样使用它。我在编译时不知道类型是什么。
        • 这要求两个属性具有相同的类型,但可能并非总是如此。
        • @HansKesting 没错,但我只是想为他的代码提出一种通用的方法
        猜你喜欢
        • 2017-12-10
        • 1970-01-01
        • 2015-05-22
        • 1970-01-01
        • 1970-01-01
        • 2015-01-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多