Co-authored-by: zzdxxz <2079238449@qq.com> Co-committed-by: zzdxxz <2079238449@qq.com>
131 lines
6.2 KiB
C#
131 lines
6.2 KiB
C#
using System;
|
||
using System.Linq;
|
||
using System.Linq.Expressions;
|
||
|
||
namespace Utils
|
||
{
|
||
public static class Resolver
|
||
{
|
||
/// <summary>
|
||
/// 将字符串表达式解析为一个谓词函数,该函数可以用于筛选实体对象。
|
||
/// </summary>
|
||
/// <param name="expression">表示条件的字符串表达式。格式示例:"entity.Id > 10" 或 "entity.Name == 'John'"。</param>
|
||
/// <returns>返回一个 Func<Entity.Entity, bool> 类型的委托,表示解析后的谓词函数。</returns>
|
||
/// <exception cref="FormatException">当输入表达式的格式不正确时抛出此异常。</exception>
|
||
/// <exception cref="NotSupportedException">当表达式中包含不支持的操作符或数据类型时抛出此异常。</exception>
|
||
/// <remarks>
|
||
/// 表达式的格式必须符合以下规则:
|
||
/// - 表达式由三部分组成:属性路径、操作符和值,用空格分隔。
|
||
/// - 属性路径格式为 "entity.PropertyName",其中 PropertyName 是实体类中的一个公共属性或字段。
|
||
/// - 操作符可以是以下之一:">", "<", ">=", "<=", "==", "!="。
|
||
/// - 值的类型必须与属性的类型匹配,并且支持以下类型:string, int, long, float, double, decimal, bool, DateTime, Guid 和枚举类型。
|
||
///
|
||
/// 注意事项:
|
||
/// - 字符串值需要用单引号或双引号括起来,例如 'John' 或 "John"。
|
||
/// - 对于可为空类型(Nullable),会自动处理其底层类型的转换。
|
||
/// - 字符串比较默认使用不区分大小写的 Equals 方法。
|
||
/// </remarks>
|
||
public static Func<Entity.Entity, bool> ParsePredicate(string expression)
|
||
{
|
||
// 格式示例:"entity.Id > 10" 或 "entity.Name == 'John'"
|
||
var parts = expression.Split(new[] { ' ' }, 3, StringSplitOptions.RemoveEmptyEntries);
|
||
if (parts.Length != 3)
|
||
throw new FormatException(
|
||
"Invalid expression format. Expected format: 'entity.Property Operator Value'");
|
||
|
||
// 解析属性和操作符
|
||
var propPath = parts[0].Split('.')[1]; // "Id" 或 "Name"
|
||
var op = parts[1]; // ">", "==" 等
|
||
|
||
// 创建表达式参数
|
||
var param = Expression.Parameter(typeof(Entity.Entity), "entity");
|
||
|
||
// 获取属性访问表达式
|
||
var propAccess = propPath.Split('.')
|
||
.Aggregate<string, Expression>(param, Expression.PropertyOrField);
|
||
|
||
// 获取属性类型
|
||
var propType = propAccess.Type;
|
||
|
||
// 解析值并转换为适当类型
|
||
object value;
|
||
var valueStr = parts[2].Trim();
|
||
|
||
try
|
||
{
|
||
if (propType == typeof(string))
|
||
// 处理字符串值(去除引号)
|
||
value = valueStr.Trim('\'', '"');
|
||
else if (propType == typeof(int))
|
||
value = int.Parse(valueStr);
|
||
else if (propType == typeof(long))
|
||
value = long.Parse(valueStr);
|
||
else if (propType == typeof(float))
|
||
value = float.Parse(valueStr);
|
||
else if (propType == typeof(double))
|
||
value = double.Parse(valueStr);
|
||
else if (propType == typeof(decimal))
|
||
value = decimal.Parse(valueStr);
|
||
else if (propType == typeof(bool))
|
||
value = bool.Parse(valueStr);
|
||
else if (propType == typeof(DateTime))
|
||
value = DateTime.Parse(valueStr);
|
||
else if (propType == typeof(Guid))
|
||
value = Guid.Parse(valueStr);
|
||
else if (propType.IsEnum)
|
||
value = Enum.Parse(propType, valueStr);
|
||
else
|
||
throw new NotSupportedException($"Type {propType.Name} is not supported");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
throw new FormatException($"Failed to parse value '{valueStr}' for type {propType.Name}", ex);
|
||
}
|
||
|
||
// 创建常量表达式(确保类型匹配)
|
||
var constant = Expression.Constant(value, propType);
|
||
|
||
// 处理可为空类型的情况
|
||
if (propType.IsGenericType && propType.GetGenericTypeDefinition() == typeof(Nullable<>))
|
||
{
|
||
var underlyingType = Nullable.GetUnderlyingType(propType);
|
||
propAccess = Expression.Property(propAccess, "Value");
|
||
constant = Expression.Constant(Convert.ChangeType(value, underlyingType), underlyingType);
|
||
}
|
||
|
||
// 创建比较表达式
|
||
Expression comparison;
|
||
if (propType == typeof(string) && (op == "==" || op == "!="))
|
||
{
|
||
// 字符串特殊处理:使用Equals方法进行不区分大小写的比较
|
||
var equalsMethod =
|
||
typeof(string).GetMethod("Equals", new[] { typeof(string), typeof(StringComparison) });
|
||
var methodCall = Expression.Call(
|
||
propAccess,
|
||
equalsMethod,
|
||
constant,
|
||
Expression.Constant(StringComparison.OrdinalIgnoreCase));
|
||
|
||
comparison = op == "==" ? methodCall : Expression.Not(methodCall);
|
||
}
|
||
else
|
||
{
|
||
// 其他类型使用标准二元运算符
|
||
comparison = op switch
|
||
{
|
||
">" => Expression.GreaterThan(propAccess, constant),
|
||
"<" => Expression.LessThan(propAccess, constant),
|
||
">=" => Expression.GreaterThanOrEqual(propAccess, constant),
|
||
"<=" => Expression.LessThanOrEqual(propAccess, constant),
|
||
"==" => Expression.Equal(propAccess, constant),
|
||
"!=" => Expression.NotEqual(propAccess, constant),
|
||
_ => throw new NotSupportedException($"Operator {op} not supported")
|
||
};
|
||
}
|
||
|
||
// 编译为委托
|
||
var lambda = Expression.Lambda<Func<Entity.Entity, bool>>(comparison, param);
|
||
return lambda.Compile();
|
||
}
|
||
}
|
||
} |