You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于指定字段列表从对象列表中动态筛选属性生成新列表?

嘿,这个问题我之前做项目的时候也遇到过——硬编码属性的写法虽然直观,但完全没法适配动态的字段列表对吧?下面给你几个实用的解决方案,你可以根据自己的场景选:

方案1:用ExpandoObject生成动态对象

这个方案最贴近你想要的「对象」体验,生成的动态对象可以像普通类一样用点语法访问属性,同时支持动态添加指定字段:

using System.Dynamic;
using System.Reflection;

// 先缓存MyObject的属性信息,避免重复反射提升性能
var myObjectProps = typeof(MyObject)
    .GetProperties(BindingFlags.Public | BindingFlags.Instance)
    .ToDictionary(p => p.Name, StringComparer.OrdinalIgnoreCase);

var dynamicResult = new List<ExpandoObject>();

foreach (var item in myList)
{
    dynamic expando = new ExpandoObject();
    var expandoDict = (IDictionary<string, object>)expando;

    foreach (var field in requiredFields)
    {
        if (myObjectProps.TryGetValue(field, out var prop))
        {
            expandoDict[field] = prop.GetValue(item);
        }
        // 可选:如果遇到不存在的字段,这里可以加日志或者抛出异常
    }

    dynamicResult.Add(expando);
}

优点:

  • 可以像普通对象一样访问属性(比如var f1 = dynamicResult[0].F1;)
  • 完全适配动态字段列表
  • 代码可读性不错

方案2:用Dictionary<string, object>存储键值对

如果不需要对象式的访问,用字典是最简单直接的写法,代码更精简:

using System.Reflection;

var dictResult = myList.Select(item =>
{
    return typeof(MyObject)
        .GetProperties(BindingFlags.Public | BindingFlags.Instance)
        .Where(p => requiredFields.Contains(p.Name, StringComparer.OrdinalIgnoreCase))
        .ToDictionary(p => p.Name, p => p.GetValue(item));
}).ToList();

优点:

  • 代码极简,不需要额外的循环逻辑
  • 字典是.NET原生类型,不需要处理动态类型的转换问题

方案3:表达式树优化反射性能(高频场景用)

如果你的数据量很大、调用频率很高,反射的性能开销可能会有点明显,这时候可以用表达式树动态构建属性访问逻辑,性能和硬编码的Select几乎一致:

using System.Linq.Expressions;
using System.Reflection;

// 缓存属性信息
var propCache = typeof(MyObject)
    .GetProperties(BindingFlags.Public | BindingFlags.Instance)
    .ToDictionary(p => p.Name, StringComparer.OrdinalIgnoreCase);

// 构建动态选择器
var parameter = Expression.Parameter(typeof(MyObject), "item");
var bindings = requiredFields.Select(field =>
{
    if (!propCache.TryGetValue(field, out var prop))
        throw new ArgumentException($"属性 {field} 在MyObject中不存在");
    return Expression.Bind(typeof(ExpandoObject).GetProperty(field), Expression.Property(parameter, prop));
    // 注:这里如果要生成强类型对象,需要提前定义对应类型,否则还是用ExpandoObject更灵活
});

var initExpr = Expression.MemberInit(Expression.New(typeof(ExpandoObject)), bindings);
var selector = Expression.Lambda<Func<MyObject, ExpandoObject>>(initExpr, parameter).Compile();

var optimizedResult = myList.Select(selector).ToList();

优点:

  • 性能接近硬编码的LINQ查询
  • 适合高频调用、大数据量的场景

额外注意点:

  • 代码里默认用了忽略大小写的属性匹配,如果需要严格区分大小写,把StringComparer.OrdinalIgnoreCase去掉即可
  • 如果requiredFields里包含不存在的属性,你可以根据需求选择忽略、打日志或者抛出异常
  • 反射相关的操作尽量缓存属性信息,避免每次都调用GetProperties,能显著提升性能

内容的提问来源于stack exchange,提问作者Rajdeep

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:18:36