如何使用Dynamic Linq从List<IDictionary<string,object>>动态选择指定列
实现方案
针对你的需求,分两种常用场景给出可直接落地的实现:
场景1:内存集合(IEnumerable<IDictionary<string, object>>)
直接实现扩展方法对每个字典做字段筛选即可:
public static class EnumerableExtensions { /// <summary> /// 动态选择字典集合的指定字段 /// </summary> /// <param name="fields">逗号分隔的字段名</param> public static IEnumerable<IDictionary<string, object>> Select(this IEnumerable<IDictionary<string, object>> source, string fields) { if (source == null) throw new ArgumentNullException(nameof(source)); if (string.IsNullOrWhiteSpace(fields)) throw new ArgumentException("字段列表不能为空", nameof(fields)); var fieldList = fields.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); foreach (var item in source) { var result = new Dictionary<string, object>(); foreach (var field in fieldList) { if (item.TryGetValue(field, out var value)) { result.Add(field, value); } } yield return result; } } }
调用方式和你要求的完全一致:
var result = lstData.Select("Name,School");
返回结果为仅包含指定字段的字典集合。
场景2:数据库IQueryable集合(如EF/EF Core查询)
如果是要对接数据库的IQueryable,为了避免拉取全表再过滤,需要用表达式树动态构建查询逻辑,实现如下:
public static class QueryableExtensions { /// <summary> /// 动态构造IQueryable的Select查询,仅返回指定字段 /// </summary> /// <param name="fields">逗号分隔的字段名</param> public static IQueryable<IDictionary<string, object>> Select(this IQueryable<IDictionary<string, object>> source, string fields) { if (source == null) throw new ArgumentNullException(nameof(source)); if (string.IsNullOrWhiteSpace(fields)) throw new ArgumentException("字段列表不能为空", nameof(fields)); var fieldList = fields.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); var parameter = Expression.Parameter(typeof(IDictionary<string, object>), "x"); var addMethod = typeof(Dictionary<string, object>).GetMethod(nameof(Dictionary<string, object>.Add), new[] { typeof(string), typeof(object) })!; // 构造字典初始化的元素绑定 var bindings = new List<ElementInit>(); foreach (var field in fieldList) { var indexerAccess = Expression.Property(parameter, "Item", Expression.Constant(field)); bindings.Add(Expression.ElementInit(addMethod, Expression.Constant(field), indexerAccess)); } // 构造完整的Lambda表达式 var dictInit = Expression.ListInit(Expression.New(typeof(Dictionary<string, object>)), bindings); var selectLambda = Expression.Lambda<Func<IDictionary<string, object>, IDictionary<string, object>>>(dictInit, parameter); return source.Select(selectLambda); } }
这个实现会把动态选字段的逻辑直接翻译成SQL的SELECT Name,School FROM xxx,不会查询多余字段,性能和硬编码的Lambda查询一致。
如果需要返回动态强类型对象而非字典,可以搭配ExpandoObject或者反射emit生成动态类使用,常规场景下用字典的实现已经足够简洁高效。
内容的提问来源于stack exchange,提问作者Amir
相关产品推荐
相关产品推荐

