using Serein.Library.Utils;
using System.Data;
namespace Serein.NodeFlow.Tool.SereinExpression
{
///
/// 使用表达式操作/获取 对象的值
/// 获取值 @get .xx.xxx
/// 设置值 @set .xx.xxx = [data]
///
/// 操作的对象
///
public class SerinArithmeticExpressionEvaluator where T : struct, IComparable
{
private static readonly DataTable table = new DataTable();
public static T Evaluate(string expression, T inputValue)
{
// 替换占位符@为输入值
expression = expression.Replace("@", inputValue.ToString());
try
{
// 使用 DataTable.Compute 方法计算表达式
var result = table.Compute(expression, string.Empty);
return (T)result;
}
catch
{
throw new ArgumentException("Invalid arithmetic expression.");
}
}
}
public class SerinExpressionEvaluator
{
///
///
///
/// 表达式
/// 操作对象
/// 是否改变了对象(Set语法)
///
///
///
public static object? Evaluate(string expression, object targetObJ, out bool isChange)
{
var parts = expression.Split([' '], 2);
if (parts.Length != 2)
{
throw new ArgumentException("Invalid expression format.");
}
var operation = parts[0].ToLower();
var operand = parts[1][0] == '.' ? parts[1][1..] : parts[1];
var result = operation switch
{
"@num" => ComputedNumber(targetObJ, operand),
"@call" => InvokeMethod(targetObJ, operand),
"@get" => GetMember(targetObJ, operand),
"@set" => SetMember(targetObJ, operand),
_ => throw new NotSupportedException($"Operation {operation} is not supported.")
};
isChange = operation switch
{
/*"@num" => true,
"@call" => true,
"@get" => true,*/
"@set" => false,
_ => true,
};
return result;
}
private static readonly char[] separator = ['(', ')'];
private static readonly char[] separatorArray = [','];
///
/// 调用目标方法
///
/// 目标实例
/// 方法名称
///
///
private static object? InvokeMethod(object? target, string methodCall)
{
if (target is null) return null;
var methodParts = methodCall.Split(separator, StringSplitOptions.RemoveEmptyEntries);
if (methodParts.Length != 2)
{
throw new ArgumentException("Invalid method call format.");
}
var methodName = methodParts[0];
var parameterList = methodParts[1];
var parameters = parameterList.Split(separatorArray, StringSplitOptions.RemoveEmptyEntries)
.Select(p => p.Trim())
.ToArray();
var method = target.GetType().GetMethod(methodName) ?? throw new ArgumentException($"Method {methodName} not found on target.");
var parameterValues = method.GetParameters()
.Select((p, index) => Convert.ChangeType(parameters[index], p.ParameterType))
.ToArray();
return method.Invoke(target, parameterValues);
}
///
/// 获取值
///
/// 目标实例
/// 属性路径
///
///
private static object? GetMember(object? target, string memberPath)
{
if (target is null) return null;
// 分割成员路径,按 '.' 处理多级访问
var members = memberPath.Split('.');
foreach (var member in members)
{
// 检查成员是否包含数组索引,例如 "cars[0]"
var arrayIndexStart = member.IndexOf('[');
if (arrayIndexStart != -1)
{
// 解析数组/集合名与索引部分
var arrayName = member.Substring(0, arrayIndexStart);
var arrayIndexEnd = member.IndexOf(']');
if (arrayIndexEnd == -1 || arrayIndexEnd <= arrayIndexStart + 1)
{
throw new ArgumentException($"Invalid array syntax for member {member}");
}
// 提取数组索引
var indexStr = member.Substring(arrayIndexStart + 1, arrayIndexEnd - arrayIndexStart - 1);
if (!int.TryParse(indexStr, out int index))
{
throw new ArgumentException($"Invalid array index '{indexStr}' for member {member}");
}
// 获取数组或集合对象
var arrayProperty = target?.GetType().GetProperty(arrayName);
if (arrayProperty is null)
{
var arrayField = target?.GetType().GetField(arrayName);
if (arrayField is null)
{
throw new ArgumentException($"Member {arrayName} not found on target.");
}
else
{
target = arrayField.GetValue(target);
}
}
else
{
target = arrayProperty.GetValue(target);
}
// 访问数组或集合中的指定索引
if (target is Array array)
{
if (index < 0 || index >= array.Length)
{
throw new ArgumentException($"Index {index} out of bounds for array {arrayName}");
}
target = array.GetValue(index);
}
else if (target is IList