簡體   English   中英

如何迭代元組項

[英]how to iterate over tuple items

當我在編譯時不知道元組由哪些類型組成時,如何迭代元組中的項目? 我只需要一個 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;
    }
}

您可以使用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));
}

這里的一個問題是您必須處理多種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;
    }
}

您的代碼沒有按預期工作,因為當您用作 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;
            }
        }
    }

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

  • t.長度
  • t[i]

它來自一個接口ITuple 接口

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM