如何迭代 IEnumerable<IEnumerable<T>> 将数据序列化为 CSV 时

How To Iterate over IEnumerable<IEnumerable<T>> When Serializing Data to CSV

我正在编写 C# class 用于将数据序列化为 CSV 格式。 我想让 class 尽可能通用,以便它适用于不同类型的数据。

我先写了下面的方法:

public void Serialize<T>(IEnumerable<T> pList)
    {
        _content.AppendLine(string.Join(_seperator, pList.Select(x => ObjectToCsvString(x)).ToArray()));
    }

然后我意识到序列化列表的列表之类的对象会很好。所以我添加了这个方法:

public void Serialize<T>(IEnumerable<IEnumerable<T>> pList)
    {
        if (pList != null && pList.Any())
        {
            foreach (IEnumerable<T> list in pList)
            {
                Serialize(list);
            }
        }
    }

所以这没有用。如果我传入一个列表列表,它仍然会直接进入第一个方法。我认为这可能与 IEnumerable(IEnumerable(T)) 在技术上也是 IEnumerable(T) 这一事实有关。但我不太确定。之后我尝试了这个方法:

public void Serialize<T>(IEnumerable<T> pList)
    {
        if (pList != null && pList.Any())
        {
            if (pList is IEnumerable<IEnumerable<T>>) //example: list of lists of strings
            {
                foreach (IEnumerable<T> list in pList)
                {
                    Serialize(list);
                }
            }
            else //write CSV line
                _content.AppendLine(string.Join(_seperator, pList.Select(x => ObjectToCsvString(x)).ToArray()));
        }
    }

与此方法类似,当我传入字符串列表时,if 语句从未执行过。我能够使用列表列表的唯一方法是使用此方法:

public void Serialize<T>(IEnumerable<T> pList)
    {
        if (pList != null && pList.Any())
        {
            if (pList is IEnumerable<IEnumerable<Object>>) //example: list of lists of strings
            {
                foreach (IEnumerable<Object> list in pList)
                {
                    Serialize(list);
                }
            }
            else //write CSV line
                _content.AppendLine(string.Join(_seperator, pList.Select(x => ObjectToCsvString(x)).ToArray()));
        }
    }

我的问题是 1) 为什么这两种方法不适用于列表列表? 2)我什至应该为此使用泛型吗?我觉得我对泛型的理解并不健全。 3) 是否有更好的方法来实现列表列表?

根本行不通,因为在

public void Serialize<T>(IEnumerable<T> pList)
{
    if (pList != null && pList.Any())
    {
        if (pList is IEnumerable<IEnumerable<T>>) //example: list of lists of strings
        {
            foreach (IEnumerable<T> list in pList)
            {
                Serialize(list);
            }
        }
        else //write CSV line
            _content.AppendLine(string.Join(_seperator, pList.Select(x => ObjectToCsvString(x)).ToArray()));
    }
}

你接受一个 IEnumerable 作为参数,一个 IEnumerable 永远不会是一个 IEnumerable> T 不是一个神奇的词,它是传递的任何东西,所以如果你传递一个包含 T 的列表,那么 T 就是 List并且 List 是 IEnumerable 而不是 IEnumerable>

处理这个问题的一个简单方法是担心所有这些在循环内而不是在循环外并一次处理所有事情是避免使用 T 的通用版本(因为你将它传递给一个似乎能够将任何物体带到更远的地方)并做这样的事情(例如更改为写入控制台)。这甚至适用于任意列表和包含一些列表元素和一些常规元素的列表

void Main()
{
    List<object> mylist = new List<object> 
    {
        "test",
        DateTime.Now,
        new List<TimeSpan>()
        {
            TimeSpan.FromSeconds(10),
            TimeSpan.FromMinutes(10)
        }
    };

    Serialize(mylist);
}

public string ObjectToCSVString(object obj)
{
    return obj.ToString();
}

public void Serialize(IEnumerable Sequence)
{
    foreach (var item in Sequence)
    {
        if (item is IEnumerable && !(item is string)) // careful, string is IEnumerable<char>
        {
            Serialize(item as IEnumerable);
        }
        else
        {
            Console.WriteLine(ObjectToCSVString(item));
        }
    }
}