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

能否解析字符串为函数并引用运行时变量?ExpandoObject实践疑问

问题原因与解决方案

报错原因

你调用DynamicExpressionParser.ParseLambda时,解析器的上下文并没有关联到你的ExpandoObject——默认情况下,解析器不会自动识别你存入sellerEx的Seller属性,必须通过显式注册变量或传入上下文参数的方式,让解析器能找到公式中的标识符。

可行实现方案

以下基于System.Linq.Dynamic.Core库(当前主流的动态表达式解析库)提供两种可行方案,均支持多数据源(如Schedule、ProductList):

方案1:通过解析配置注册上下文变量

将所有数据源(Seller、Schedule等)和后续计算出的属性注册到解析器的变量列表中,让公式直接引用标识符:

using System.Dynamic;
using System.Linq.Dynamic.Core;

// 初始化基础数据
var seller = new Seller { MonthlyAmount = 1500 };
var schedule = new Schedule { DiscountRate = 0.02m }; // 示例其他数据源

// 创建动态对象存储数据源与计算结果
var dynamicContainer = new ExpandoObject() as IDictionary<string, object>;
dynamicContainer["Seller"] = seller;
dynamicContainer["Schedule"] = schedule;

// 按依赖顺序排序公式(先算无依赖的Bonus,再算依赖它的AmountPlusBonus)
var orderedFormulas = formulas.OrderBy(f => f.Value.Contains("Bonus") ? 1 : 0).ToList();

var parsingConfig = new ParsingConfig();
// 先注册所有基础数据源到解析变量
foreach (var kvp in dynamicContainer.Where(kvp => !(kvp.Value is LambdaExpression)))
{
    parsingConfig.Variables[kvp.Key] = kvp.Value;
}

foreach (var formula in orderedFormulas)
{
    // 解析公式为无参数Lambda
    var lambda = DynamicExpressionParser.ParseLambda(parsingConfig, Type.EmptyTypes, typeof(object), formula.Value);
    // 执行计算并存储结果
    var result = lambda.DynamicInvoke();
    dynamicContainer[formula.Key] = result;
    // 将新结果注册为变量,供后续公式引用
    parsingConfig.Variables[formula.Key] = result;
}

// 测试访问结果
dynamic dynContainer = dynamicContainer;
Console.WriteLine(dynContainer.Bonus); // 输出45
Console.WriteLine(dynContainer.AmountPlusBonus); // 输出1545
Console.WriteLine(dynContainer.Schedule.DiscountRate); // 输出0.02

方案2:将动态对象作为Lambda参数传入

把ExpandoObject作为Lambda的输入参数,公式中用默认参数名it访问上下文属性,更符合Lambda的参数传递逻辑:

using System.Dynamic;
using System.Linq.Dynamic.Core;

var seller = new Seller { MonthlyAmount = 1500 };
var dynamicContext = new ExpandoObject() as IDictionary<string, object>;
dynamicContext["Seller"] = seller;
dynamicContext["Schedule"] = new Schedule { DiscountRate = 0.02m };

// 处理公式依赖顺序
var orderedFormulas = formulas.OrderBy(f => f.Value.Contains("Bonus") ? 1 : 0).ToList();

foreach (var formula in orderedFormulas)
{
    // 调整公式,用it.xxx访问上下文属性
    var adjustedFormula = formula.Value
        .Replace("Seller", "it.Seller")
        .Replace("Bonus", "it.Bonus")
        .Replace("Schedule", "it.Schedule");
    // 解析Lambda,参数类型为ExpandoObject
    var lambda = DynamicExpressionParser.ParseLambda(new[] { typeof(ExpandoObject) }, typeof(object), adjustedFormula);
    // 传入上下文执行计算
    var result = lambda.DynamicInvoke(dynamicContext);
    dynamicContext[formula.Key] = result;
}

// 访问结果
dynamic dynContext = dynamicContext;
Console.WriteLine(dynContext.Bonus);

多数据源支持说明

完全可行。只需将Schedule、ProductList等对象添加到ExpandoObject中,通过上述方案的任一方式,即可在公式中直接引用这些数据源的属性,例如公式可以写为:Seller.MonthlyAmount * (1 - Schedule.DiscountRate)。

注意事项

  • 必须处理公式的依赖顺序:如果公式B依赖公式A的结果,必须先计算A再计算B;复杂依赖场景可通过拓扑排序确定执行顺序。
  • 确保项目引用System.Linq.Dynamic.Core NuGet包,原System.Linq.Dynamic库已停止维护。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 21:09:59