gpt4 book ai didi

c# - 如何自动将 IEnumerable 转换为 csv 文件?

转载 作者:太空狗 更新时间:2023-10-29 17:36:01 25 4
gpt4 key购买 nike

我正在尝试创建一个接受任何通用列表的用户控件,以便我可以遍历它并创建一个 CSV 导出。是否可以公开可以接受任何类型的公共(public)属性? (即 List<Product>List<Customer> 等)如果是,如何?

public IEnumerable<T> AnyList { get; set; }

就我所拥有的实用方法而言,这是我所拥有的:

public static byte[] ToCsv<T>(string separator, IEnumerable<T> objectlist)
{
//Type t = typeof(T); Deleted this line.

//Here's the line of code updated.
PropertyInfo[] propertyNames = objectlist.First().GetType().GetProperties();

string header = String.Join(separator, propertyNames.Select(f => f.Name).ToArray());

StringBuilder csvdata = new StringBuilder();
csvdata.AppendLine(header);

foreach (var o in objectlist)
csvdata.AppendLine(ToCsvFields(separator, propertyNames, o));

return Encoding.ASCII.GetBytes(csvdata.ToString());
}

public static string ToCsvFields(string separator, PropertyInfo[] fields, object o)
{
StringBuilder linie = new StringBuilder();

foreach (var f in fields)
{
if (linie.Length > 0)
linie.Append(separator);

var x = f.GetValue(o, null);

if (x != null)
linie.Append(x.ToString());
}

return linie.ToString();
}

最佳答案

如果您想从对象列表中“创建 CSV 导出”,您应该使用反射来计算列。

2016 年 2 月 12 日最新更新:

将分隔符默认为逗号更有意义,并且使初始标题行的输出可选。它现在还通过使用 Concat 支持字段简单属性 :

public static IEnumerable<string> ToCsv<T>(IEnumerable<T> objectlist, string separator = ",", bool header = true)
{
FieldInfo[] fields = typeof(T).GetFields();
PropertyInfo[] properties = typeof(T).GetProperties();
if (header)
{
yield return String.Join(separator, fields.Select(f => f.Name).Concat(properties.Select(p=>p.Name)).ToArray());
}
foreach (var o in objectlist)
{
yield return string.Join(separator, fields.Select(f=>(f.GetValue(o) ?? "").ToString())
.Concat(properties.Select(p=>(p.GetValue(o,null) ?? "").ToString())).ToArray());
}
}

因此您可以像这样使用逗号分隔:

foreach (var line in ToCsv(objects))
{
Console.WriteLine(line);
}

或像这样用于另一个分隔符(例如 TAB):

foreach (var line in ToCsv(objects, "\t"))
{
Console.WriteLine(line);
}

实例

将列表写入逗号分隔的 CSV 文件

using (TextWriter tw = File.CreateText("C:\testoutput.csv"))
{
foreach (var line in ToCsv(objects))
{
tw.WriteLine(line);
}
}

或者用制表符分隔

using (TextWriter tw = File.CreateText("C:\testoutput.txt"))
{
foreach (var line in ToCsv(objects, "\t"))
{
tw.WriteLine(line);
}
}

如果您有复杂的字段/属性,您需要将它们从选择子句中过滤掉。


之前的更新

首先最后的想法(所以不会遗漏):

如果您更喜欢通用解决方案(这可确保对象属于同一类型):

public static IEnumerable<string> ToCsv<T>(string separator, IEnumerable<T> objectlist)
{
FieldInfo[] fields = typeof(T).GetFields();
PropertyInfo[] properties = typeof(T).GetProperties();
yield return String.Join(separator, fields.Select(f => f.Name).Union(properties.Select(p=>p.Name)).ToArray());
foreach (var o in objectlist)
{
yield return string.Join(separator, fields.Select(f=>(f.GetValue(o) ?? "").ToString())
.Union(properties.Select(p=>(p.GetValue(o,null) ?? "").ToString())).ToArray());
}
}

这个包括公共(public)字段和公共(public)属性。

一般来说,使用反射你不需要知道列表中对象的类型(你必须假设它们都是相同的类型)。

你可以使用:

public IEnumerable<object> AnyList { get; set; }

你想做的事情的基本过程是这样的:

  • 从列表中的第一个对象获取类型(例如 GetType() )。
  • 迭代该类型的属性。
  • 写出 CSV header ,例如基于属性(或属性)的名称。
  • 对于列表中的每一项...
    • 迭代该类型的属性
    • 获取每个属性的值(作为对象)
    • 用分隔符写出对象的 ToString() 版本

您可以使用相同的算法生成二维数组(即,如果您希望控件以表格/网格形式显示类似 CSV 的内容)。

您遇到的唯一问题可能是从 IEnumerables/特定类型的列表转换为 IEnumerable。在这些情况下只需使用 .Cast<object>在您的特定类型枚举上。

更新:

当您使用来自 http://www.joe-stevens.com/2009/08/03/generate-a-csv-from-a-generic-list-of-objects-using-reflection-and-extension-methods/ 的代码时

您需要对他的代码进行以下更改:

// Make it a simple extension method for a list of object
public static string GetCSV(this List<object> list)
{
StringBuilder sb = new StringBuilder();

//Get the properties from the first object in the list for the headers
PropertyInfo[] propInfos = list.First().GetType().GetProperties();

如果你想支持一个空列表,添加第二个参数(例如 Type type )这是你期望的对象类型并使用它而不是 list.First().GetType() .

注意:我在他的代码中没有看到任何其他地方引用了 T,但如果我错过了它,编译器会为您找到它:)

更新(完整和简化的 CSV 生成器):

public static IEnumerable<string> ToCsv(string separator, IEnumerable<object> objectlist)
{
if (objectlist.Any())
{
Type type = objectlist.First().GetType();
FieldInfo[] fields = type.GetFields();
yield return String.Join(separator, fields.Select(f => f.Name).ToArray());
foreach (var o in objectlist)
{
yield return string.Join(separator, fields.Select(f=>(f.GetValue(o) ?? "").ToString()).ToArray());
}
}
}

这样做的好处是内存开销低,因为它会在结果出现时产生结果,而不是创建大量字符串。您可以像这样使用它:

foreach (var line in ToCsv(",", objects))
{
Console.WriteLine(line);
}

我更喜欢实践中的通用解决方案,因此将其放在首位。

关于c# - 如何自动将 IEnumerable<T> 转换为 csv 文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10915852/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com