mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-03-03 00:00:49 +08:00
164 lines
5.0 KiB
C#
164 lines
5.0 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace Serein.Script
|
|
{
|
|
public static class BinaryOperationEvaluator
|
|
{
|
|
public static object EvaluateValue(object left, string op, object right)
|
|
{
|
|
if (op == null) throw new ArgumentNullException(nameof(op));
|
|
|
|
// 特判字符串拼接
|
|
if (op == "+" && (left is string || right is string))
|
|
{
|
|
return (left?.ToString() ?? "") + (right?.ToString() ?? "");
|
|
}
|
|
|
|
// 支持 null 运算(可按需扩展)
|
|
if (left == null || right == null)
|
|
{
|
|
throw new InvalidOperationException($"无法对 null 执行操作:{op}");
|
|
}
|
|
|
|
// 尝试统一类型(浮点优先)
|
|
var leftType = left.GetType();
|
|
var rightType = right.GetType();
|
|
|
|
Type resultType = GetWiderType(leftType, rightType);
|
|
dynamic leftValue = Convert.ChangeType(left, resultType);
|
|
dynamic rightValue = Convert.ChangeType(right, resultType);
|
|
|
|
return op switch
|
|
{
|
|
"+" => leftValue + rightValue,
|
|
"-" => leftValue - rightValue,
|
|
"*" => leftValue * rightValue,
|
|
"/" => rightValue == 0 ? throw new DivideByZeroException() : leftValue / rightValue,
|
|
|
|
">" => leftValue > rightValue,
|
|
"<" => leftValue < rightValue,
|
|
">=" => leftValue >= rightValue,
|
|
"<=" => leftValue <= rightValue,
|
|
"==" => Equals(leftValue, rightValue),
|
|
"!=" => !Equals(leftValue, rightValue),
|
|
|
|
_ => throw new NotImplementedException($"未实现的操作符: {op}")
|
|
};
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// 推导两个类型的“最通用类型”(类型提升)
|
|
/// </summary>
|
|
private static Type GetWiderType(Type t1, Type t2)
|
|
{
|
|
if (t1 == typeof(string) || t2 == typeof(string)) return typeof(string);
|
|
if (t1 == typeof(decimal) || t2 == typeof(decimal)) return typeof(decimal);
|
|
if (t1 == typeof(double) || t2 == typeof(double)) return typeof(double);
|
|
if (t1 == typeof(float) || t2 == typeof(float)) return typeof(float);
|
|
if (t1 == typeof(ulong) || t2 == typeof(ulong)) return typeof(ulong);
|
|
if (t1 == typeof(long) || t2 == typeof(long)) return typeof(long);
|
|
if (t1 == typeof(uint) || t2 == typeof(uint)) return typeof(uint);
|
|
if (t1 == typeof(int) || t2 == typeof(int)) return typeof(int);
|
|
|
|
// fallback
|
|
return typeof(object);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static Type EvaluateType(Type leftType, string op, Type rightType)
|
|
{
|
|
if (leftType == null || rightType == null)
|
|
throw new ArgumentNullException("操作数类型不能为 null");
|
|
|
|
// 字符串拼接
|
|
if (op == "+" && (leftType == typeof(string) || rightType == typeof(string)))
|
|
return typeof(string);
|
|
|
|
// 比较操作总是返回 bool
|
|
if (op is ">" or "<" or ">=" or "<=" or "==" or "!=")
|
|
return typeof(bool);
|
|
|
|
// 数值类型推导
|
|
if (IsNumeric(leftType) && IsNumeric(rightType))
|
|
{
|
|
return PromoteNumericType(leftType, rightType);
|
|
}
|
|
|
|
// 逻辑操作
|
|
if (op is "&&" or "||")
|
|
{
|
|
if (leftType == typeof(bool) && rightType == typeof(bool))
|
|
return typeof(bool);
|
|
throw new InvalidOperationException($"逻辑操作 '{op}' 仅适用于 bool 类型");
|
|
}
|
|
|
|
throw new NotImplementedException($"不支持操作符 '{op}' 对 {leftType.Name} 和 {rightType.Name} 进行类型推导");
|
|
}
|
|
|
|
private static bool IsNumeric(Type type)
|
|
{
|
|
return type == typeof(byte) || type == typeof(sbyte) ||
|
|
type == typeof(short) || type == typeof(ushort) ||
|
|
type == typeof(int) || type == typeof(uint) ||
|
|
type == typeof(long) || type == typeof(ulong) ||
|
|
type == typeof(float) || type == typeof(double) ||
|
|
type == typeof(decimal);
|
|
}
|
|
|
|
// 提升到更高精度类型
|
|
private static Type[] types = new[]
|
|
{
|
|
typeof(decimal),
|
|
typeof(double),
|
|
typeof(float),
|
|
typeof(ulong),
|
|
typeof(long),
|
|
typeof(uint),
|
|
typeof(int),
|
|
typeof(ushort),
|
|
typeof(short),
|
|
typeof(byte),
|
|
typeof(sbyte)
|
|
};
|
|
|
|
private static Type PromoteNumericType(Type left, Type right)
|
|
{
|
|
var ranks = types;
|
|
foreach (var type in ranks)
|
|
{
|
|
if (type == left || type == right)
|
|
return type;
|
|
}
|
|
|
|
return typeof(object); // fallback
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|