Lor*_*nzo 12 linq linq-to-entities entity-framework dynamic-linq
我试图以编程方式构建表达式树.
我在输入中有一个条件类列表,它们具有以下形式:
public class Filter
{
public string field { get; set; }
public string operator { get; set; }
public string value { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
当我构建Expression对象时,我Expression按以下方式为每个条件创建一个
foreach ( Filter sf in rules ) {
Expression ex = sf.ToExpression( query );
if ( mainExpression == null ) {
mainExpression = ex;
}
else {
if ( logicalCondition == "AND" ) {
mainExpression = Expression.And( mainExpression, ex );
}
else if ( logicalCondition == "OR" ) {
mainExpression = Expression.Or( mainExpression, ex );
}
}
}
Run Code Online (Sandbox Code Playgroud)
Filter.ToExpression()方法就像这样实现
public override Expression ToExpression( IQueryable query ) {
ParameterExpression parameter = Expression.Parameter( query.ElementType, "p" );
MemberExpression memberAccess = null;
foreach ( var property in field.Split( '.' ) )
memberAccess = MemberExpression.Property( memberAccess ?? ( parameter as Expression ), property );
ConstantExpression filter = Expression.Constant( Convert.ChangeType( value, memberAccess.Type ) );
WhereOperation condition = (WhereOperation)StringEnum.Parse( typeof( WhereOperation ), operator );
LambdaExpression lambda = BuildLambdaExpression( memberAccess, filter, parameter, condition, value );
return lambda;
}
Run Code Online (Sandbox Code Playgroud)
一切正常时,我有一个条件,但是当我尝试使用的一个表达式组合And,Or,AndAlso,OrElse静态方法我收到的InvalidOperationException,说:
二进制运算符Or未定义类型'System.Func
2[MyObject,System.Boolean]' and 'System.Func2 [MyObject,System.Boolean]'.
我有点困惑.有人能更好地解释异常的原因并提出解决方案吗?
非常感谢!
小智 29
你结合a => a == 3和a => a == 4成(a => a == 3) || (a => a == 4),但你应该改为试图使它a => (a == 3 || a == 4).这不是很难手动完成,但有人已经为你做了.寻找"结合表达式".
编辑:根据要求,一个如何手动执行此操作的简单示例.
编辑2:它使用ExpressionVisitor.NET 4中的新功能,但在MSDN中,您可以找到早期版本的可用实现.我假设MSDN代码不符合您的"第三方"的条件.您只需要将protected virtual Expression Visit(Expression exp)方法更改为public.而且Enumerable.Zip对你来说没有必要,它现在已经消失了.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
namespace DemoApp
{
<include ExpressionVisitor definition here for .NET 3.5>
public class ExpressionParameterReplacer : ExpressionVisitor
{
public ExpressionParameterReplacer(IList<ParameterExpression> fromParameters, IList<ParameterExpression> toParameters)
{
ParameterReplacements = new Dictionary<ParameterExpression, ParameterExpression>();
for (int i = 0; i != fromParameters.Count && i != toParameters.Count; i++)
ParameterReplacements.Add(fromParameters[i], toParameters[i]);
}
private IDictionary<ParameterExpression, ParameterExpression> ParameterReplacements
{
get;
set;
}
protected override Expression VisitParameter(ParameterExpression node)
{
ParameterExpression replacement;
if (ParameterReplacements.TryGetValue(node, out replacement))
node = replacement;
return base.VisitParameter(node);
}
}
class Program
{
static void Main(string[] args)
{
Expression<Func<int, bool>> exprA = a => a == 3;
Expression<Func<int, bool>> exprB = b => b == 4;
Expression<Func<int, bool>> exprC =
Expression.Lambda<Func<int, bool>>(
Expression.OrElse(
exprA.Body,
new ExpressionParameterReplacer(exprB.Parameters, exprA.Parameters).Visit(exprB.Body)),
exprA.Parameters);
Console.WriteLine(exprA.ToString());
Console.WriteLine(exprB.ToString());
Console.WriteLine(exprC.ToString());
Func<int, bool> funcA = exprA.Compile();
Func<int, bool> funcB = exprB.Compile();
Func<int, bool> funcC = exprC.Compile();
Debug.Assert(funcA(3) && !funcA(4) && !funcA(5));
Debug.Assert(!funcB(3) && funcB(4) && !funcB(5));
Debug.Assert(funcC(3) && funcC(4) && !funcC(5));
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
9610 次 |
| 最近记录: |