高効率IEnumerable回転データテーブル
3180 ワード
IEnumerableのTは汎用型であり,Tにどのような属性があるかを事前に知ることはできないため,作成したDataTableでもカラムを予め設定することはできない.このような場合、まず反射を思い浮かべます.
反射効率が低く、自然と表現ツリーというものを思い浮かべます.表現ツリーの1つの役割は、反射の機能を実現し、反射による効率の問題を回避することです.
まずobj=>objのような形を構築するつもりです.Propertyの式ツリー.
次に、上記の反射コードを次のように変更できます.
いいですね.反射することなく仕事を完成しました.しかし、効率は本当に向上していますか?必ずしもそうではないと思います.後者は前者のpiをGetValue(collection.ElementAt(i),null)はp=>p.FastGetValue(i)に変更され、FastGetValueは毎回式ツリーを構築してLambdaをコンパイルし、IEnumerableの各データに対して同じ属性依頼を繰り返し構築します.両者の効率は私は測ったことがありませんが、この方法は完璧ではありません.改善された方法は、属性とGetGetDelegate構造の委任をキー値ペアとしてキャッシュして後続のループで使用するなど、多くあります.次は私が考えている良い解決方法です.
転載は本文の出典を明記してください.http://www.cnblogs.com/newton/archive/2013/01/09/2853083.html
public static DataTable ToDataTable(IEnumerable collection)
{
var props = typeof(T).GetProperties();
var dt = new DataTable();
dt.Columns.AddRange(props.Select(p => new DataColumn(p.Name, p.PropertyType)).ToArray());
if (collection.Count() > 0)
{
for (int i = 0; i < collection.Count(); i++)
{
ArrayList tempList = new ArrayList();
foreach (PropertyInfo pi in props)
{
object obj = pi.GetValue(collection.ElementAt(i), null);
tempList.Add(obj);
}
object[] array = tempList.ToArray();
dt.LoadDataRow(array, true);
}
}
return dt;
}
反射効率が低く、自然と表現ツリーというものを思い浮かべます.表現ツリーの1つの役割は、反射の機能を実現し、反射による効率の問題を回避することです.
まずobj=>objのような形を構築するつもりです.Propertyの式ツリー.
// Func getAge = u => u.Age;
static Func GetGetDelegate(PropertyInfo p)
{
var param_obj = Expression.Parameter(typeof(T), "obj");
//lambda u.Age
var pGetter = Expression.Property(param_obj, p);
// lambda
return Expression.Lambda>(pGetter, param_obj).Compile();
}
static object FastGetValue(this PropertyInfo property, T t)
{
return GetGetDelegate(property)(t);
}
次に、上記の反射コードを次のように変更できます.
public static DataTable ToTable(this IEnumerable collection)
{
var props = typeof(T).GetProperties();
var dt = new DataTable();
dt.Columns.AddRange(
props.Select(p => new DataColumn(p.Name, p.PropertyType)).ToArray()
);
collection.ToList().ForEach(
i => dt.Rows.Add(props.Select(p => p.FastGetValue(i)).ToArray())
);
return dt;
}
いいですね.反射することなく仕事を完成しました.しかし、効率は本当に向上していますか?必ずしもそうではないと思います.後者は前者のpiをGetValue(collection.ElementAt(i),null)はp=>p.FastGetValue(i)に変更され、FastGetValueは毎回式ツリーを構築してLambdaをコンパイルし、IEnumerableの各データに対して同じ属性依頼を繰り返し構築します.両者の効率は私は測ったことがありませんが、この方法は完璧ではありません.改善された方法は、属性とGetGetDelegate構造の委任をキー値ペアとしてキャッシュして後続のループで使用するなど、多くあります.次は私が考えている良い解決方法です.
static Func GetGetDelegate(PropertyInfo[] ps)
{
var param_obj = Expression.Parameter(typeof(T), "obj");
Expression newArrayExpression = Expression.NewArrayInit(typeof(object), ps.Select(p => Expression.Property(param_obj, p)));
return Expression.Lambda>(newArrayExpression, param_obj).Compile();
}
public static DataTable ToTable(this IEnumerable collection)
{
var props = typeof(T).GetProperties();
var func = GetGetDelegate(props);
var dt = new DataTable();
dt.Columns.AddRange(
props.Select(p => new DataColumn(p.Name, p.PropertyType)).ToArray()
);
collection.ToList().ForEach(i => dt.Rows.Add(func(i)));
return dt;
}
転載は本文の出典を明記してください.http://www.cnblogs.com/newton/archive/2013/01/09/2853083.html