我试图了解表达方式。我正在点击可怕的“参数未绑定在指定的LINQ to Entities查询表达式”异常。我见过Skeet以及其他人在线回答这个问题。但是,我只是无法“看到”问题。我正在使用Colin Meek的例子http://blogs.msdn.com/b/meek/archive/2008/05/02/linq-to-entities-combining-predicates.aspx和Matt Warren的VisitorExpression类http://blogs.msdn.com/b/mattwar/archive/2007/07/31/linq-building-an-iqueryable-provider-part-ii.aspx。我在VS 2010中使用控制台应用程序,框架4.0。对不起,如果这是因为之前有人被问过,那就是打死了马。谢谢你的帮助。
要彻底,所有代码如下:
class Program
{
static void Main(string[] args)
{
Expression<Func<Car, bool>> theCarIsRed = c => c.Color == "Red";
Expression<Func<Car, bool>> theCarIsCheap = c => c.Price < 10.0;
Expression<Func<Car, bool>> theCarIsRedOrCheap = theCarIsRed.Or(theCarIsCheap);
Car one = new Car() { CarId = 1, Color = "Red", Price = 10.0 };
Car two = new Car() { CarId = 2, Color = "Blue", Price = 9.0 };
Car three = new Car() { CarId = 3, Color = "Black", Price = 5.0 };
Car four = new Car() { CarId = 4, Color = "Red", Price = 5.0 };
EntityDBContext context = new EntityDBContext();
context.CarEntity.Add(one);
context.CarEntity.Add(two);
context.CarEntity.Add(three);
context.CarEntity.Add(four);
using (var db = context)
{
// Bang
var query = db.CarEntity.AsQueryable().Where(theCarIsRedOrCheap).ToList();
foreach (var item in query)
{
Console.WriteLine(item.Color, item.Price);
}
}
Console.ReadKey();
}
}
public class Car
{
[Key]
public int CarId { get; set; }
public string Color { get; set; }
public double Price { get; set; }
}
public static class Utility
{
public static Expression<T> Compose<T>(this Expression<T> first,
Expression<T> second, Func<Expression, Expression, Expression> merge)
{
var map = first.Parameters.Select((f, i) => new { f, s = second.Parameters[i] }).ToDictionary(p => p.s, p => p.f);
var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body);
return Expression.Lambda<T>(merge(first.Body, second.Body), first.Parameters);
}
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
{
return first.Compose(second, Expression.And);
}
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
{
return first.Compose(second, Expression.Or);
}
}
public class ParameterRebinder : ExpressionVisitor
{
private readonly Dictionary<ParameterExpression, ParameterExpression> map;
public ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> map)
{
this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>();
}
public static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp)
{
return new ParameterRebinder(map).Visit(exp);
}
protected override Expression VisitParameter(ParameterExpression parmEx)
{
ParameterExpression replacement;
if (map.TryGetValue(parmEx, out replacement))
{
parmEx = replacement;
}
return base.VisitParameter(parmEx);
}
}
public abstract class ExpressionVisitor
{
protected ExpressionVisitor()
{
}
protected virtual Expression Visit(Expression exp)
{
if (exp == null)
{
return exp;
}
switch (exp.NodeType)
{
case ExpressionType.Negate:
case ExpressionType.NegateChecked:
case ExpressionType.Not:
case ExpressionType.Convert:
case ExpressionType.ConvertChecked:
case ExpressionType.ArrayLength:
case ExpressionType.Quote:
case ExpressionType.TypeAs:
return this.VisitUnary((UnaryExpression) exp);
case ExpressionType.Add:
case ExpressionType.AddChecked:
case ExpressionType.Subtract:
case ExpressionType.SubtractChecked:
case ExpressionType.Multiply:
case ExpressionType.MultiplyChecked:
case ExpressionType.Divide:
case ExpressionType.Modulo:
case ExpressionType.And:
case ExpressionType.AndAlso:
case ExpressionType.Or:
case ExpressionType.OrElse:
case ExpressionType.LessThan:
case ExpressionType.LessThanOrEqual:
case ExpressionType.GreaterThan:
case ExpressionType.GreaterThanOrEqual:
case ExpressionType.Equal:
case ExpressionType.NotEqual:
case ExpressionType.Coalesce:
case ExpressionType.ArrayIndex:
case ExpressionType.RightShift:
case ExpressionType.LeftShift:
case ExpressionType.ExclusiveOr:
return this.VisitBinary((BinaryExpression) exp);
case ExpressionType.TypeIs:
return this.VisitTypeIs((TypeBinaryExpression) exp);
case ExpressionType.Conditional:
return this.VisitConditional((ConditionalExpression) exp);
case ExpressionType.Constant:
return this.VisitConstant((ConstantExpression) exp);
case ExpressionType.Parameter:
return this.VisitParameter((ParameterExpression) exp);
case ExpressionType.MemberAccess:
return this.VisitMemberAccess((MemberExpression) exp);
case ExpressionType.Call:
return this.VisitMethodCall((MethodCallExpression) exp);
case ExpressionType.Lambda:
return this.VisitLambda((LambdaExpression) exp);
case ExpressionType.New:
return this.VisitNew((NewExpression) exp);
case ExpressionType.NewArrayInit:
case ExpressionType.NewArrayBounds:
return this.VisitNewArray((NewArrayExpression) exp);
case ExpressionType.Invoke:
return this.VisitInvocation((InvocationExpression) exp);
case ExpressionType.MemberInit:
return this.VisitMemberInit((MemberInitExpression) exp);
case ExpressionType.ListInit:
return this.VisitListInit((ListInitExpression) exp);
default:
throw new Exception(String.Format("Unhandled expression type: '{0}'", exp.NodeType));
}
}
protected virtual MemberBinding VisitBinding(MemberBinding binding)
{
switch (binding.BindingType)
{
case MemberBindingType.Assignment:
return this.VisitMemberAssignment((MemberAssignment) binding);
case MemberBindingType.MemberBinding:
return this.VisitMemberMemberBinding((MemberMemberBinding) binding);
case MemberBindingType.ListBinding:
return this.VisitMemberListBinding((MemberListBinding) binding);
default:
throw new Exception(String.Format("Unhandled binding type '{0}'", binding.BindingType));
}
}
protected virtual Expression VisitListInit(ListInitExpression init)
{
NewExpression n = this.VisitNew(init.NewExpression);
IEnumerable<ElementInit> initializers = this.VisitElementInitializerList(init.Initializers);
if (n != init.NewExpression || initializers != init.Initializers)
{
return Expression.ListInit(n, initializers);
}
return init;
}
protected virtual Expression VisitMemberInit(MemberInitExpression memberInitExpression)
{
NewExpression n = this.VisitNew(memberInitExpression.NewExpression);
IEnumerable<MemberBinding> bindings = this.VisitBindingList(memberInitExpression.Bindings);
if (n != memberInitExpression.NewExpression || bindings != memberInitExpression.Bindings)
{
return Expression.MemberInit(n, bindings);
}
return memberInitExpression;
}
protected virtual Expression VisitInvocation(InvocationExpression invocationExpression)
{
IEnumerable<Expression> args = this.VisitExpressionList(invocationExpression.Arguments);
Expression expr = this.Visit(invocationExpression.Expression);
if (args != invocationExpression.Arguments || expr != invocationExpression.Expression)
{
return Expression.Invoke(expr, args);
}
return invocationExpression;
}
protected virtual Expression VisitNewArray(NewArrayExpression newArrayExpression)
{
IEnumerable<Expression> exprs = this.VisitExpressionList(newArrayExpression.Expressions);
if (exprs != newArrayExpression.Expressions)
{
if (newArrayExpression.NodeType == ExpressionType.NewArrayInit)
{
return Expression.NewArrayInit(newArrayExpression.Type.GetElementType(), exprs);
}
else
{
return Expression.NewArrayBounds(newArrayExpression.Type.GetElementType());
}
}
return newArrayExpression;
}
protected virtual NewExpression VisitNew(NewExpression newExpression)
{
IEnumerable<Expression> args = this.VisitExpressionList(newExpression.Arguments);
if (args != newExpression.Arguments)
{
if (newExpression.Members != null)
{
return Expression.New(newExpression.Constructor, args, newExpression.Members);
}
else
{
return Expression.New(newExpression.Constructor, args);
}
}
return newExpression;
}
protected virtual Expression VisitLambda(LambdaExpression lambdaExpression)
{
Expression body = this.Visit(lambdaExpression.Body);
if (body != lambdaExpression.Body)
{
return Expression.Lambda(lambdaExpression.Type, body, lambdaExpression.Parameters);
}
return lambdaExpression;
}
protected virtual Expression VisitMethodCall(MethodCallExpression methodCallExpression)
{
Expression obj = this.Visit(methodCallExpression.Object);
IEnumerable<Expression> args = this.VisitExpressionList(methodCallExpression.Arguments);
if (obj != methodCallExpression.Object || args != methodCallExpression.Arguments)
{
return Expression.Call(obj, methodCallExpression.Method, args);
}
return methodCallExpression;
}
protected virtual Expression VisitMemberAccess(MemberExpression memberExpression)
{
Expression exp = this.Visit(memberExpression.Expression);
if (exp != memberExpression.Expression)
{
return Expression.MakeMemberAccess(exp, memberExpression.Member);
}
return memberExpression;
}
protected virtual Expression VisitParameter(ParameterExpression parameterExpression)
{
return parameterExpression;
}
protected virtual Expression VisitConstant(ConstantExpression constantExpression)
{
return constantExpression;
}
protected virtual Expression VisitConditional(ConditionalExpression conditionalExpression)
{
Expression test = this.Visit(conditionalExpression.Test);
Expression ifTrue = this.Visit(conditionalExpression.IfTrue);
Expression ifFalse = this.Visit(conditionalExpression.IfFalse);
if (test != conditionalExpression.Test || ifTrue != conditionalExpression.IfTrue || ifFalse != conditionalExpression.IfFalse)
{
return Expression.Condition(test, ifTrue, ifFalse);
}
return conditionalExpression;
}
protected virtual Expression VisitTypeIs(TypeBinaryExpression typeBinaryExpression)
{
Expression expr = this.Visit(typeBinaryExpression.Expression);
if (expr != typeBinaryExpression)
{
return Expression.TypeIs(expr, typeBinaryExpression.TypeOperand);
}
return typeBinaryExpression;
}
protected virtual Expression VisitBinary(BinaryExpression binaryExpression)
{
Expression left = this.Visit(binaryExpression.Left);
Expression right = this.Visit(binaryExpression.Right);
Expression conversion = this.Visit(binaryExpression.Conversion);
if (left != binaryExpression.Left || right != binaryExpression.Right || conversion != binaryExpression.Conversion)
{
if (binaryExpression.NodeType == ExpressionType.Coalesce && binaryExpression.Conversion != null)
{
return Expression.Coalesce(left, right, conversion as LambdaExpression);
}
else
{
return Expression.MakeBinary(binaryExpression.NodeType, left, right, binaryExpression.IsLiftedToNull,
binaryExpression.Method);
}
}
return binaryExpression;
}
protected virtual Expression VisitUnary(UnaryExpression unaryExpression)
{
Expression operand = this.Visit(unaryExpression.Operand);
if (operand != unaryExpression.Operand)
{
return Expression.MakeUnary(unaryExpression.NodeType, operand, unaryExpression.Type,
unaryExpression.Method);
}
return unaryExpression;
}
protected virtual ReadOnlyCollection<Expression> VisitExpressionList(ReadOnlyCollection<Expression> original)
{
List<Expression> list = null;
for (int i = 0, n = original.Count; i < n; i++)
{
Expression p = this.Visit(original[i]);
if (list != null)
{
list.Add(p);
}
else if (p != original[i])
{
list = new List<Expression>(n);
for (int j = 0; j < i; j++)
{
list.Add(original[j]);
}
list.Add(p);
}
}
return list != null ? list.AsReadOnly() : original;
}
protected virtual IEnumerable<MemberBinding> VisitBindingList(ReadOnlyCollection<MemberBinding> original)
{
List<MemberBinding> list = null;
for (int i = 0, n = original.Count; i < n; i++)
{
MemberBinding b = this.VisitBinding(original[i]);
if (list != null)
{
list.Add(b);
}
else if (b != original[i])
{
list = new List<MemberBinding>(n);
for (int j = 0; j < i; j++)
{
list.Add(original[j]);
}
list.Add(b);
}
}
if (list != null)
{
return list;
}
return original;
}
protected virtual MemberAssignment VisitMemberAssignment(MemberAssignment assignment)
{
Expression e = this.Visit(assignment.Expression);
if (e != assignment.Expression)
{
return Expression.Bind(assignment.Member, e);
}
return assignment;
}
protected virtual MemberMemberBinding VisitMemberMemberBinding(MemberMemberBinding binding)
{
IEnumerable<MemberBinding> bindings = this.VisitBindingList(binding.Bindings);
if (bindings != binding.Bindings)
{
return Expression.MemberBind(binding.Member, bindings);
}
return binding;
}
protected virtual MemberListBinding VisitMemberListBinding(MemberListBinding binding)
{
IEnumerable<ElementInit> initializers = this.VisitElementInitializerList(binding.Initializers);
if (initializers != binding.Initializers)
{
return Expression.ListBind(binding.Member, initializers);
}
return binding;
}
protected virtual IEnumerable<ElementInit> VisitElementInitializerList(ReadOnlyCollection<ElementInit> original)
{
List<ElementInit> list = null;
for (int i = 0, n = original.Count; i < n; i++)
{
ElementInit init = this.VisitElementInitializer(original[i]);
if (list != null)
{
list.Add(init);
}
else if (init != original[i])
{
list = new List<ElementInit>(n);
for (int j = 0; j < i; j++)
{
list.Add(original[j]);
}
list.Add(init);
}
}
if (list != null)
{
return list;
}
return original;
}
protected virtual ElementInit VisitElementInitializer(ElementInit initializer)
{
ReadOnlyCollection<Expression> arguments = this.VisitExpressionList(initializer.Arguments);
if (arguments != initializer.Arguments)
{
return Expression.ElementInit(initializer.AddMethod, arguments);
}
return initializer;
}
}
答案 0 :(得分:0)
在实用程序中尝试使用以下内容替换compose方法。
{
var map = first.Parameters.Select((f, i) => new { f, s = second.Parameters[i] }).ToDictionary(p => p.s, p => p.f);
var secondRebound = ParameterRebinder.ReplaceParameters(map, second);
return Expression.Lambda<T>(merge(first.Body, secondRebound.Body), first.Parameters);
}