如何在C#中使用动态属性过滤对象列表
动态属性过滤WarehouseModel列表的修正方案
问题分析
原代码核心错误是尝试用字符串变量propName直接访问对象属性(x.propName),这属于语法错误——C#不支持这种动态属性访问方式。另外,perms.DistinctBy(x => x.FieldName)会丢弃同一属性名下的多个过滤值(比如示例中的"36"和"37"),导致过滤逻辑不完整。
修正方案1:基于反射的基础实现
这种方式简单直接,适合数据量不大的场景:
using ConsoleApp2; void GetAll() { IEnumerable<WarehouseModel> warehouseModels = new List<WarehouseModel>() { new WarehouseModel() { Code = "35", Name = "Name 35" }, new WarehouseModel() { Code = "36", Name = "Name 36" }, new WarehouseModel() { Code = "37", Name = "Name 37" }, new WarehouseModel() { Code = "38", Name = "Name 38" }, new WarehouseModel() { Code = "39", Name = "Name 39" }, new WarehouseModel() { Code = "40", Name = "Name 40" } }; IEnumerable<PermModel> perms = new List<PermModel>() { new PermModel() { FieldName = "Code", FieldValue = "36" }, new PermModel() { FieldName = "Code", FieldValue = "37" } }; var newList = new List<WarehouseModel>(); // 按FieldName分组,保留同一属性下的所有过滤值 var permGroups = perms.GroupBy(p => p.FieldName); foreach (var group in permGroups) { // 获取对应的属性信息,先判断是否存在避免空引用 var propInfo = typeof(WarehouseModel).GetProperty(group.Key); if (propInfo == null) continue; // 反射获取属性值并与过滤值匹配 var filtered = warehouseModels.Where(x => { // 获取属性值并转为字符串(根据实际属性类型调整转换逻辑) var propValue = propInfo.GetValue(x)?.ToString(); // 匹配当前属性下的任意一个FieldValue return group.Any(perm => perm.FieldValue == propValue); }).ToList(); newList.AddRange(filtered); } } GetAll();
修正方案2:表达式树实现(高性能版)
如果需要处理大量数据,表达式树的性能优于直接反射,因为编译后的表达式是强类型委托:
using ConsoleApp2; using System.Linq.Expressions; void GetAll() { IEnumerable<WarehouseModel> warehouseModels = new List<WarehouseModel>() { new WarehouseModel() { Code = "35", Name = "Name 35" }, new WarehouseModel() { Code = "36", Name = "Name 36" }, new WarehouseModel() { Code = "37", Name = "Name 37" }, new WarehouseModel() { Code = "38", Name = "Name 38" }, new WarehouseModel() { Code = "39", Name = "Name 39" }, new WarehouseModel() { Code = "40", Name = "Name 40" } }; IEnumerable<PermModel> perms = new List<PermModel>() { new PermModel() { FieldName = "Code", FieldValue = "36" }, new PermModel() { FieldName = "Code", FieldValue = "37" } }; // 构建过滤表达式并编译 var filterExpression = BuildFilterExpression<WarehouseModel>(perms); var newList = warehouseModels.Where(filterExpression.Compile()).ToList(); } // 通用的过滤表达式构建方法 private static Expression<Func<T, bool>> BuildFilterExpression<T>(IEnumerable<PermModel> perms) { var parameter = Expression.Parameter(typeof(T), "x"); Expression combinedCondition = Expression.Constant(false); var permGroups = perms.GroupBy(p => p.FieldName); foreach (var group in permGroups) { var propInfo = typeof(T).GetProperty(group.Key); if (propInfo == null) continue; // 构建属性访问表达式 var propertyAccess = Expression.Property(parameter, propInfo); // 将属性值转为字符串(根据实际属性类型调整) var toStringCall = Expression.Call(propertyAccess, "ToString", Type.EmptyTypes); // 构建当前属性的多值OR条件 Expression groupCondition = Expression.Constant(false); foreach (var perm in group) { var valueConstant = Expression.Constant(perm.FieldValue); var equalsExpr = Expression.Equal(toStringCall, valueConstant); groupCondition = Expression.OrElse(groupCondition, equalsExpr); } // 合并到总条件中 combinedCondition = Expression.OrElse(combinedCondition, groupCondition); } return Expression.Lambda<Func<T, bool>>(combinedCondition, parameter); } GetAll();
关键修正点
- 替换错误的属性访问方式:用反射
PropertyInfo.GetValue(x)或表达式树Expression.Property实现动态属性访问 - 保留多过滤值:用
GroupBy替代DistinctBy,确保同一属性名下的所有FieldValue都参与过滤 - 增加异常防护:判断
PropertyInfo是否为null,避免因属性名拼写错误导致的空引用异常
内容的提问来源于stack exchange,提问作者Abdul Muttalib
相关产品推荐
相关产品推荐

