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

C#中基于Expression<Func<ExpandoObject, object>>的属性筛选实现求助

解决方案

要实现从ExpandoObject中筛选指定属性并返回新的ExpandoObject,可以通过动态构建表达式树创建高效的投影委托,以下是具体实现:

核心实现代码

using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq.Expressions;

public static class ExpandoObjectFilter
{
    public static Expression<Func<ExpandoObject, object>> CreateProjectionExpression(List<ListSearchImportFieldModel> fields)
    {
        // 定义输入参数:源ExpandoObject
        var sourceParam = Expression.Parameter(typeof(ExpandoObject), "source");
        // 将ExpandoObject转换为IDictionary<string, object>以访问属性
        var sourceAsDict = Expression.Convert(sourceParam, typeof(IDictionary<string, object>));

        // 初始化新的ExpandoObject并转为字典类型
        var newExpando = Expression.New(typeof(ExpandoObject));
        var newExpandoAsDict = Expression.Convert(newExpando, typeof(IDictionary<string, object>));

        // 声明变量存储新的字典实例
        var newDictVar = Expression.Variable(typeof(IDictionary<string, object>), "newDict");
        var assignNewDict = Expression.Assign(newDictVar, newExpandoAsDict);

        // 构建所有属性添加逻辑
        var addPropertyExpressions = new List<Expression>();
        foreach (var field in fields)
        {
            if (string.IsNullOrWhiteSpace(field.Field_Name))
                continue;

            var fieldName = Expression.Constant(field.Field_Name);
            // 检查源字典是否包含当前字段,避免KeyNotFoundException
            var containsKey = Expression.Call(
                sourceAsDict,
                typeof(IDictionary<string, object>).GetMethod("ContainsKey"),
                fieldName);

            // 从源字典取值并添加到新字典
            var getValue = Expression.Index(sourceAsDict, fieldName);
            var addProperty = Expression.Call(
                newDictVar,
                typeof(IDictionary<string, object>).GetMethod("Add"),
                fieldName,
                getValue);

            // 仅当字段存在时执行添加操作
            addPropertyExpressions.Add(Expression.IfThen(containsKey, addProperty));
        }

        // 组合完整的执行块
        var block = Expression.Block(
            new[] { newDictVar },
            assignNewDict,
            Expression.Block(addPropertyExpressions),
            Expression.Convert(newDictVar, typeof(object)));

        return Expression.Lambda<Func<ExpandoObject, object>>(block, sourceParam);
    }
}

使用示例

// 构造源ExpandoObject
var source = new ExpandoObject() as IDictionary<string, object>;
source["Name"] = "Alice";
source["Age"] = 30;
source["Email"] = "alice@example.com";
source["Address"] = "123 Main St";

// 指定需要筛选的字段列表
var targetFields = new List<ListSearchImportFieldModel>
{
    new ListSearchImportFieldModel { Field_Name = "Name" },
    new ListSearchImportFieldModel { Field_Name = "Age" },
    new ListSearchImportFieldModel { Field_Name = "NonExistentField" } // 不存在的字段会被自动忽略
};

// 创建投影表达式并编译为可执行委托
var projection = ExpandoObjectFilter.CreateProjectionExpression(targetFields).Compile();

// 执行筛选
var filteredResult = projection(source as ExpandoObject) as ExpandoObject;

// 输出结果
var resultDict = filteredResult as IDictionary<string, object>;
foreach (var kvp in resultDict)
{
    Console.WriteLine($"{kvp.Key}: {kvp.Value}");
}
// 输出:
// Name: Alice
// Age: 30

关键说明

  • 类型转换:利用ExpandoObject的底层实现特性,将其转为IDictionary<string, object>,通过字典的索引器和方法操作属性。
  • 异常规避:通过ContainsKey检查字段是否存在,避免处理不存在的属性时抛出KeyNotFoundException。
  • 性能优化:表达式树编译后生成的委托性能接近手写代码,适合批量处理大量ExpandoObject实例。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 19:48:34