我正在尝试创建一个接受任何通用列表的用户控件,以便我可以遍历它并创建CSV导出.是否可以公开可以接受任何类型的公共财产?(即List<Product>,List<Customer>等).如果是,如何?
public IEnumerable<T> AnyList { get; set; }
Run Code Online (Sandbox Code Playgroud)
这就是我所拥有的实用方法:
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();
}
Run Code Online (Sandbox Code Playgroud)
Gon*_*ing 16
如果您想从对象列表中"创建CSV导出",则应使用反射来计算列.
将分隔符默认为逗号更有意义,并且有助于使初始标题行的输出可选.它现在还通过使用以下方式支持字段和简单属性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());
}
}
Run Code Online (Sandbox Code Playgroud)
所以你这样用它来逗号分隔:
foreach (var line in ToCsv(objects))
{
Console.WriteLine(line);
}
Run Code Online (Sandbox Code Playgroud)
或像这样的另一个分隔符(例如TAB):
foreach (var line in ToCsv(objects, "\t"))
{
Console.WriteLine(line);
}
Run Code Online (Sandbox Code Playgroud)
将列表写入以逗号分隔的CSV文件
using (TextWriter tw = File.CreateText("C:\testoutput.csv"))
{
foreach (var line in ToCsv(objects))
{
tw.WriteLine(line);
}
}
Run Code Online (Sandbox Code Playgroud)
或者以制表符分隔
using (TextWriter tw = File.CreateText("C:\testoutput.txt"))
{
foreach (var line in ToCsv(objects, "\t"))
{
tw.WriteLine(line);
}
}
Run Code Online (Sandbox Code Playgroud)
如果您有复杂的字段/属性,则需要将它们从select子句中过滤掉.
如果您更喜欢通用解决方案(这可确保对象具有相同的类型):
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());
}
}
Run Code Online (Sandbox Code Playgroud)
这包括公共领域和公共财产.
通常使用反射,您不需要知道列表中对象的类型(您必须假设它们都是相同的类型).
你可以使用:
public IEnumerable<object> AnyList { get; set; }
Run Code Online (Sandbox Code Playgroud)
您想要做的事情的基本过程如下:
GetType()).您可以使用相同的算法生成2D数组(即,如果您希望控件以表格/网格形式显示CSV).
您遇到的唯一问题可能是从IEnumerables /特定类型的列表转换为IEnumerable.在这些情况下,只需使用.Cast<object>您的特定类型的可枚举.
您需要对其代码进行以下更改:
// 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();
Run Code Online (Sandbox Code Playgroud)
如果要支持空列表,请添加第二个参数(例如Type type),它是您期望的对象类型,并使用它而不是list.First().GetType().
注意:我没有在他的代码中看到引用T的其他地方,但是如果我错过了它,编译器会为你找到它:)
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());
}
}
}
Run Code Online (Sandbox Code Playgroud)
这具有低内存开销的优点,因为它在发生时产生结果,而不是创建大量字符串.您可以像以下一样使用它:
foreach (var line in ToCsv(",", objects))
{
Console.WriteLine(line);
}
Run Code Online (Sandbox Code Playgroud)
我更喜欢实践中的通用解决方案,所以首先放置了它.
| 归档时间: |
|
| 查看次数: |
5669 次 |
| 最近记录: |