如何在字符串上构建表达式时实现LessThan等

本文关键字:实现 LessThan 表达式 构建 字符串 | 更新日期: 2023-09-27 18:13:20

我有一个包,我正在构建表达式树,使用EntityFramework,通过PredicateBuilder:

public Expression<Func<T, bool>> constructaPredicate<T>(ExpressionType operation, string fieldName, Expression value)
{
    var type = typeof(T);
    var parameter = Expression.Parameter(type);
    var member = Expression.PropertyOrField(parameter, fieldName);
    Expression comparison = Expression.MakeBinary(operation, member, value);
    var expression = Expression.Lambda<Func<T, bool>>(comparison, parameter);
    return expression;
}

这很好,除了比较字符串与GreaterThan等。在这种情况下,我得到一个异常:

The binary operator GreaterThan is not defined for the types 'System.String' and 'System.String'.

这很简单。浏览了一下,我只发现了一些关于这个问题的参考资料,而且没有一个是在我正在做的事情的背景下。

当然,问题是没有String。GreaterThan方法。通常的答案是使用String.CompareTo(),但我还没有弄清楚如何使其工作。

我一直在尝试使用表达式的重载。MakeBinary,它接受一个methodinfo对象,但我还没有弄清楚。

帮助吗?

添加

我试过用特殊的字符串。GreaterThan等,我仍然得到相同的错误:

Expression comparison = null;
if (value.Type == typeof (string))
{
    if (operation == ExpressionType.GreaterThanOrEqual ||
        operation == ExpressionType.GreaterThan ||
        operation == ExpressionType.LessThanOrEqual ||
        operation == ExpressionType.LessThan)
    {
        var method = value.Type.GetMethod("CompareTo", new[] {typeof (string)});
        var zero = Expression.Constant(0);
        var result = Expression.Call(member, method, converted);
        comparison = Expression.MakeBinary(operation, result, zero);
    }
}
if (comparison == null)
    comparison = Expression.MakeBinary(operation, member, converted);
var lambda = Expression.Lambda<Func<T, bool>>(comparison, parameter);

但是我仍然看到完全相同的异常。这对我来说没有意义,因为如果我在做我认为我在做的事情,表达式中唯一的GreaterThan是比较Int32和Int32。

又增添了

我发现非常奇怪的是,在从表达式树中删除GreaterThan之后,我会看到同样的错误。

我一直在运行这段代码作为单元测试的一部分,与实体框架连接到一个内存数据库称为努力。所以我在SqlServer上试过。

我的原始代码,没有特殊情况的字符串,但使用GreaterThan的一切,抛出"GreaterThan not defined"异常,当运行对SqlServer,当运行对努力。

我修改的代码,那个特殊大小写字符串,对SqlServer工作得很好,但在对Effort运行时抛出了"GreaterThan not defined"异常。

似乎当Effort在表达式树中看到CompareTo()时,它将其转换为GreaterThan,从而导致我们熟悉的异常。

Yet More Added

在继续探索这个问题的过程中,我确定在努力中有一个错误,可以用一个非常简单的例子来揭示:

var foos = myDbContext.Foos.Where(f => f.fooid.CompareTo("Z") > 0).ToList();

这个工作得很好,当myDbContext连接到SqlServer数据库时,它会抛出我们喜欢的异常,当连接到一个Effort数据库时。我已经在Effort讨论论坛上提交了一个bug报告。

对于那些正在阅读这篇文章的人,我的第二次尝试,在上面的第一个"添加"部分,是正确的解决方案。它对SqlServer有效,而对Effort无效是由于Effort中的一个错误。

附录

上面的问题是,"转换"指的是什么。

事实上,我几乎不记得了。

在我的代码中发生的是,我有一个表达式树,我将这些比较应用于它。我使用Expression.Convert()将其转换为底层类型。

我不确定完整的方法是否有多大意义,没有类的其余部分,但这里是:

public Expression<Func<T, bool>> constructSinglePredicate<T>(object context)
{
    var type = typeof(T);
    var parameter = Expression.Parameter(type);
    var member = this.getMember<T>(type, parameter);
    var value = this.constructConstantExpression<T>(this.rightHandSide, context);
    ExpressionType operation;
    if (!operationMap.TryGetValue(this.selectionComparison, out operation))
        throw new ArgumentOutOfRangeException("selectionComparison", this.selectionComparison, "Invalid filter operation");
    try
    {
        var converted = (value.Type != member.Type)
            ? (Expression)Expression.Convert(value, member.Type)
            : (Expression)value;
        Expression comparison = null;
        if (value.Type == typeof(string))
        {
            if (operation == ExpressionType.GreaterThanOrEqual ||
                operation == ExpressionType.GreaterThan ||
                operation == ExpressionType.LessThanOrEqual ||
                operation == ExpressionType.LessThan)
            {
                MethodInfo method = value.Type.GetMethod("CompareTo", new[] { typeof(string) });
                var zero = Expression.Constant(0);
                var result = Expression.Call(member, method, converted);
                comparison = Expression.MakeBinary(operation, result, zero);
            }
        }
        if (comparison == null)
            comparison = Expression.MakeBinary(operation, member, converted);
        var lambda = Expression.Lambda<Func<T, bool>>(comparison, parameter);
        return lambda;
    }
    catch (Exception)
    {
        throw new InvalidOperationException(
            String.Format("Cannot convert value '"{0}'" of type '"{1}'" to field '"{2}'" of type '"{3}'"", this.rightHandSide,
                value.Type, this.fieldName, member.Type));
    }
}

如何在字符串上构建表达式时实现LessThan等

这行得通:

Expression comparison = null;
if (value.Type == typeof (string))
{
    if (operation == ExpressionType.GreaterThanOrEqual ||
        operation == ExpressionType.GreaterThan ||
        operation == ExpressionType.LessThanOrEqual ||
        operation == ExpressionType.LessThan)
    {
        var method = value.Type.GetMethod("CompareTo", new[] {typeof (string)});
        var zero = Expression.Constant(0);
        var result = Expression.Call(member, method, converted);
        comparison = Expression.MakeBinary(operation, result, zero);
    }
}
if (comparison == null)
    comparison = Expression.MakeBinary(operation, member, converted);
var lambda = Expression.Lambda<Func<T, bool>>(comparison, parameter);