我有以下扩展程序,它会从DataTable
生成IEnumerable
:
public static DataTable AsDataTable<T>(this IEnumerable<T> enumerable)
{
DataTable table = new DataTable();
T first = enumerable.FirstOrDefault();
if (first == null)
return table;
PropertyInfo[] properties = first.GetType().GetProperties();
foreach (PropertyInfo pi in properties)
table.Columns.Add(pi.Name, pi.PropertyType);
foreach (T t in enumerable)
{
DataRow row = table.NewRow();
foreach (PropertyInfo pi in properties)
row[pi.Name] = t.GetType().InvokeMember(pi.Name, BindingFlags.GetProperty, null, t, null);
table.Rows.Add(row);
}
return table;
}
然而,在大量数据上,性能不是很好。是否有任何明显的性能修复我无法看到?
答案 0 :(得分:2)
您可以始终使用像Fasterflect这样的库来发出IL,而不是对列表中每个项目的每个属性使用true Reflection。不确定与DataTable
的任何问题。
或者,如果此代码不是试图成为通用解决方案,那么您可以始终将IEnumerable
内的任何类型转换为DataRow
,从而避免一起反映。
答案 1 :(得分:2)
首先,一些非性能问题:
就事情而言,我可以看到反射和数据表加载方面的潜在改进:
使用这些mod,您最终会得到以下内容:
public static DataTable AsDataTable<T>(this IEnumerable<T> enumerable)
{
if (enumerable == null)
{
throw new ArgumentNullException("enumerable");
}
DataTable table = new DataTable();
if (enumerable.Any())
{
IList<PropertyInfo> properties = typeof(T)
.GetProperties()
.Where(p => p.CanRead && (p.GetIndexParameters().Length == 0))
.ToList();
foreach (PropertyInfo property in properties)
{
table.Columns.Add(property.Name, property.PropertyType);
}
IList<MethodInfo> getters = properties.Select(p => p.GetGetMethod()).ToList();
table.BeginLoadData();
try
{
object[] values = new object[properties.Count];
foreach (T item in enumerable)
{
for (int i = 0; i < getters.Count; i++)
{
values[i] = getters[i].Invoke(item, BindingFlags.Default, null, null, CultureInfo.InvariantCulture);
}
table.Rows.Add(values);
}
}
finally
{
table.EndLoadData();
}
}
return table;
}
答案 2 :(得分:1)
而不是:
row[pi.Name] = t.GetType().InvokeMember(pi.Name, BindingFlags.GetProperty, null, t, null);
使用:
row[pi.Name] = pi.GetValue(t, null);
答案 3 :(得分:1)
您可能没有选择,但可能会查看代码的体系结构,看看您是否可以避免使用DataTable
而是自己返回IEnumerable<T>
。
这样做的主要原因是:
您将从IEnumerable转到DataTable,它实际上是从流式操作转移到缓冲操作。
流式传输:使用yield return
,以便仅在需要时将结果从枚举中拉出。它不像foreach
缓冲:将所有结果提取到内存中(例如填充的集合,数据表或数组),这样就可以立即产生所有费用。
如果您可以使用IEnumerable返回类型,那么您可以自己使用yield return
关键字,这意味着您可以将所有反射的成本分摊,而不是一次性产生所有这些。