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

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

public Expression<Func> constructaPredicate(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>(comparison, parameter); return expression; } 

这种方法很好,除了比较字符串和GreaterThan等。在这种情况下,我得到一个例外:

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

这很简单。 浏览一下,我发现只有少数几个引用这个问题,没有在我正在做的事情的背景下。

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

我一直在尝试使用带有methodinfo对象的Expression.MakeBinary的重载,但我还没弄明白。

救命?

添加

所以,我试过特殊情况下String.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>(comparison, parameter); 

但我仍然看到完全相同的例外。 这对我没有意义,因为如果我正在做我认为我正在做的事情,那么表达式中唯一的GreaterThan就是将Int32与Int32进行比较。

更多已添加

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

我一直在运行此代码作为unit testing的一部分,entity framework连接到名为Effort的内存数据库。 所以我尝试对抗SqlServer。

我的原始代码,没有特殊情况字符串,但是对于所有内容都使用了GreaterThan,当针对SqlServer运行时,以及针对Effort运行时,抛出了“GreaterThan not defined”exception。

我的修改后的代码,即特殊字符串,对SqlServer工作得很好,但是在针对Effort运行时抛出了“GreaterThan not defined”exception。

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

还有更多

在继续探讨这个问题时,我已经确定Effort中存在一个错误,可以通过一个非常简单的示例来揭示:

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

这很好,当myDbContext连接到SqlServer数据库时,它会在连接到Effort数据库时抛出我们最喜欢的exception。 我已经在努力讨论论坛上提交了一份错误报告。

对于那些正在阅读本文的人,我的第二次尝试,在我上面的第一个“已添加”部分,是正确的解决方案。 它适用于SqlServer,并且它不反对Effort是由于Effort中的错误。

附录

问题是,“转换”指的是什么,在上面。

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

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

我不确定完整的方法会有多大意义,没有其他同学,但这里是:

 public Expression<Func> constructSinglePredicate(object context) { var type = typeof(T); var parameter = Expression.Parameter(type); var member = this.getMember(type, parameter); var value = this.constructConstantExpression(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>(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)); } } 

这有效:

 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>(comparison, parameter);