C#中如何传递自定义LambdaExpression?DataTable转换扩展方法场景
在C#中通过Lambda表达式筛选类属性以转换为DataTable
我来帮你解决这个问题——要实现通过Lambda表达式指定不需要添加到DataTable的类属性,我们可以从扩展方法的参数设计和Lambda解析两方面入手,下面分步骤说明:
1. 设计支持Lambda筛选的扩展方法
首先我们需要调整ConvertToDataTable2方法的参数,允许传入一组Lambda表达式来指定要排除的属性。这里需要处理值类型属性的装箱问题(比如int类型的属性会被包装为UnaryExpression),确保能正确提取属性名称。
扩展方法实现代码
using System; using System.Collections.Generic; using System.Data; using System.Linq; using System.Linq.Expressions; using System.Reflection; public static class ObjectExtensions { public static DataTable ConvertToDataTable2<T>(this T obj, params Expression<Func<T, object>>[] excludedProperties) { var dataTable = new DataTable(); var type = typeof(T); // 收集所有要排除的属性名称 var excludedNames = new HashSet<string>(); foreach (var expr in excludedProperties) { switch (expr.Body) { // 引用类型属性的Lambda表达式 case MemberExpression memberExpr: excludedNames.Add(memberExpr.Member.Name); break; // 值类型属性会被装箱,需要拆箱获取MemberExpression case UnaryExpression unaryExpr when unaryExpr.Operand is MemberExpression memberExpr: excludedNames.Add(memberExpr.Member.Name); break; } } // 添加未被排除的属性作为DataTable列 foreach (var prop in type.GetProperties(BindingFlags.Public | BindingFlags.Instance)) { if (!excludedNames.Contains(prop.Name)) { // 处理可空类型,获取底层类型 var columnType = Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType; dataTable.Columns.Add(prop.Name, columnType); } } // 填充数据行 var row = dataTable.NewRow(); foreach (var prop in type.GetProperties(BindingFlags.Public | BindingFlags.Instance)) { if (!excludedNames.Contains(prop.Name)) { row[prop.Name] = prop.GetValue(obj) ?? DBNull.Value; } } dataTable.Rows.Add(row); return dataTable; } }
2. 使用Lambda表达式调用扩展方法
现在你可以直接传入Lambda表达式,指定哪些属性不需要被添加到DataTable中。比如如果你想排除ReasonCode和Description属性,调用代码如下:
class Program { static void Main(string[] args) { CancelMaintenance cm = new CancelMaintenance(); cm.UserID = 1; cm.CancelReasonCodeID = 2; cm.CancelRefund = "C"; cm.Description = "test"; cm.ReasonCode = "TestCode"; // 传入要排除的属性的Lambda表达式 DataTable dt = cm.ConvertToDataTable2(x => x.ReasonCode, x => x.Description); } } public class CancelMaintenance { public int UserID { get; set; } public int CancelReasonCodeID { get; set; } public string CancelRefund { get; set; } public string Description { get; set; } public string ReasonCode { get; set; } }
3. 更灵活的筛选方式(可选)
如果你需要更复杂的筛选逻辑(比如只保留特定类型的属性,或者按属性名称前缀筛选),可以将扩展方法的参数改为Func<PropertyInfo, bool>,直接传入属性判断逻辑:
扩展方法重载版本
public static DataTable ConvertToDataTable2<T>(this T obj, Func<PropertyInfo, bool> includePredicate) { var dataTable = new DataTable(); var type = typeof(T); foreach (var prop in type.GetProperties(BindingFlags.Public | BindingFlags.Instance)) { if (includePredicate(prop)) { var columnType = Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType; dataTable.Columns.Add(prop.Name, columnType); } } var row = dataTable.NewRow(); foreach (var prop in type.GetProperties(BindingFlags.Public | BindingFlags.Instance)) { if (includePredicate(prop)) { row[prop.Name] = prop.GetValue(obj) ?? DBNull.Value; } } dataTable.Rows.Add(row); return dataTable; }
调用示例(只保留指定属性)
// 只保留UserID、CancelReasonCodeID、CancelRefund三个属性 DataTable dt = cm.ConvertToDataTable2(prop => prop.Name == nameof(CancelMaintenance.UserID) || prop.Name == nameof(CancelMaintenance.CancelReasonCodeID) || prop.Name == nameof(CancelMaintenance.CancelRefund));
内容的提问来源于stack exchange,提问作者Neeraj Kumar Gupta
相关产品推荐
相关产品推荐

