110,534
社区成员
发帖
与我相关
我的任务
分享
/// <summary>
/// 为 DataTable 增加合计列
/// </summary>
/// <param name="tb">源DataTable</param>
/// <param name="columnName">合计列的标题名</param>
/// <returns>锁增加的列的数据定义</returns>
public static DataColumn test(DataTable tb, string columnName)
{
var cs = tb.Columns; //获得 tb 的数据定义
var res = cs.Add(columnName, typeof(double)); //增加合计列
foreach (DataRow dr in tb.Rows)
dr[columnName] = cs.Cast<DataColumn>().Aggregate(0.0, (sum, col) => //遍历所有列进行累加,并将结果赋值到本行合计列
{
var value = dr[col];
if (value is string || value is DateTime || typeof(Control).IsAssignableFrom(value.GetType()))
return sum;
else
return sum + (double)dr[col];
});
return res;
}
实际上,是否“麻烦”,不在于人家数据是否多,而在于你自己!cs.Cast<DataColumn>()
这样写,是因为古老的 DataColumnCollection 类型对象不支持枚举,所以无法直接使用 Linq。那么使用 Cast<T> 就可以把它明确封装为可枚举的对象了,可以使用 Linq 了。
Aggregate
是 Linq 中的累积器技术,也就是 map-reduce 的 recuce!/// <summary>
/// 为 DataTable 增加合计列
/// </summary>
/// <param name="tb">源DataTable</param>
/// <param name="columnName">合计列的标题名</param>
/// <returns>锁增加的列的数据定义</returns>
public static DataColumn test(DataTable tb, string columnName)
{
var cs = tb.Columns; //获得 tb 的数据定义
var res = cs.Add(columnName, typeof(double)); //增加合计列
foreach (DataRow dr in tb.Rows)
dr[columnName] = cs.Cast<DataColumn>().Aggregate(0.0, (sum, col) => //遍历所有列进行累加,并将结果赋值到本行合计列
{
return sum + (double)dr[col];
});
return res;
}
实际上 DataTable 支持在每一列上设置一个 Expression 表达式,从而它自动给你计算。这样,你只要遍历 cs 的每一个 DataCoumn,取到每一列的名字,然后动态拼接一个字符串类类型的 Expression 表达式,设置给合计列。
你实际上并不需要枚举 DataTable 的每一行。每当你访问 DataTable 的某一行数据的合计列时,它会自动给你合计。