ExpressionResolver.cs 4.01 KB
using System;
using System.Data;
using System.Text.RegularExpressions;
using Rcs.Domain.Entities;
using Rcs.Domain.Enums;
using Rcs.Domain.Models;
using Rcs.Domain.Services;
using Rcs.Shared.Utils;

namespace Rcs.Infrastructure.Services.ParameterResolvers
{
    /// <summary>
    /// 表达式解析器 - 支持变量替换和算术运算
    /// 语法示例:
    /// - 简单变量:${Node.LayerHeight}
    /// - 算术运算:${Node.LayerHeight} * ${Node.LayerCount} + 50
    /// - 字符串拼接:${Task.TaskCode}_${Robot.RobotCode}
    /// @author zzy
    /// </summary>
    public class ExpressionResolver : IParameterValueResolver
    {
        public ParameterSourceType SourceType => ParameterSourceType.Context;

        /// <summary>
        /// 变量占位符正则表达式:匹配 ${Source.Path} 格式
        /// </summary>
        private static readonly Regex PlaceholderRegex = new(
            @"\$\{(\w+)\.([^}]+)\}",
            RegexOptions.Compiled);

        /// <summary>
        /// 算术运算符检测
        /// </summary>
        private static readonly char[] ArithmeticOperators = { '+', '-', '*', '/', '%', '(', ')' };

        public object? Resolve(ActionParameterDefinition definition, ParameterContext context)
        {
            var expression = definition.ParameterSourcePath;
            if (string.IsNullOrEmpty(expression))
                return definition.DefaultValue;

            // 1. 替换所有变量占位符为实际值
            var resolvedExpr = PlaceholderRegex.Replace(expression, match =>
            {
                var sourceName = match.Groups[1].Value;  // Task, Robot, Node, Edge, Extra
                var path = match.Groups[2].Value;        // 属性路径

                var source = GetSourceObject(context, sourceName);
                var value = PropertyPathResolver.GetValue(source, path);

                // 数值类型返回数字字符串,其他类型返回原始字符串
                return value?.ToString() ?? "0";
            });

            // 2. 判断是否包含算术运算符
            if (ContainsArithmeticOperator(resolvedExpr))
            {
                return EvaluateArithmeticExpression(resolvedExpr);
            }

            // 3. 非算术表达式,直接返回替换后的字符串
            return resolvedExpr;
        }

        /// <summary>
        /// 根据来源名称获取上下文中的对象
        /// </summary>
        private static object? GetSourceObject(ParameterContext context, string sourceName)
        {
            return sourceName.ToUpperInvariant() switch
            {
                "TASK" => context.Task,
                "ROBOT" => context.Robot,
                "NODE" => context.Node,
                "EDGE" => context.Edge,
                "EXTRA" => context.Extra,
                _ => null
            };
        }

        /// <summary>
        /// 检测表达式是否包含算术运算符
        /// </summary>
        private static bool ContainsArithmeticOperator(string expression)
        {
            return expression.IndexOfAny(ArithmeticOperators) >= 0;
        }

        /// <summary>
        /// 计算算术表达式
        /// 使用 DataTable.Compute 方法,支持 +, -, *, /, %, 括号
        /// </summary>
        private static object? EvaluateArithmeticExpression(string expression)
        {
            try
            {
                // 清理表达式中的空格
                var cleanExpr = expression.Trim();

                // 使用 DataTable.Compute 计算表达式
                var table = new DataTable();
                var result = table.Compute(cleanExpr, string.Empty);

                // 转换为 double 类型
                if (result != null && result != DBNull.Value)
                {
                    return Convert.ToDouble(result);
                }

                return null;
            }
            catch (Exception)
            {
                // 计算失败,返回原始表达式
                return expression;
            }
        }
    }
}