2010-05-01 95 views
1

我正在编写一个表达式解析器,以使我的API更易于重构,并且不易出错。 basicaly,我希望用户写这样的代码:的尝试编译Lambda表达式时出现InvalidOperationException(Lambda参数不在范围内)

repository.Get(entity => entity.Id == 10); 

代替:

repository.Get<Entity>("Id", 10); 

从二进制表达的左侧提取成员的名字是直线前进。 当我试图从表达式的右侧提取值时,问题就开始了。 上面的代码片段演示了一个最简单的情况,它涉及一个常量值 ,但涉及闭包的情况可能更复杂,而不是更复杂的情况。

在玩了一段时间后,我放弃了试图覆盖所有可能的情况,我自己 ,并决定使用该框架来编译和执行表达式的右侧来完成所有繁重的工作。 代码的相关部分看起来像这样:

public static KeyValuePair<string, object> Parse<T>(Expression<Func<T, bool>> expression) 
{ 
    var binaryExpression = (BinaryExpression)expression.Body; 

    string memberName = ParseMemberName(binaryExpression.Left); 
    object value = ParseValue(binaryExpression.Right); 

    return new KeyValuePair<string, object>(memberName, value); 
} 

private static object ParseValue(Expression expression) 
{ 
    Expression conversionExpression = Expression.Convert(expression, typeof(object)); 
    var lambdaExpression = Expression.Lambda<Func<object>>(conversionExpression); 
    Func<object> accessor = lambdaExpression.Compile(); 
    return accessor(); 
} 

现在,我得到的编译行一个InvalidOperationException(范围LAMBDA参数不是)。当我搜索解决方案时,我想出了类似的问题,涉及到手动构建表达式而不是提供所有片断,或试图依赖具有相同名称和不同参考的参数。我不认为这是这种情况,因为我正在重复使用给定的表达式。

EDIT

这是的非工作情形之一:

ExpressionParser.Parse(实体=> entity.InternalClass.Id == entity.Id);

我很感激,如果有人会给我一些指示。 谢谢。

回答

1

带常量的版本可以正常工作,并且发布的代码也可以正常工作。你能举例说明一个不起作用的例子吗?

当你看到这个,这意味着你的Right正在尝试使用一个参数;在Expression<Func<T, bool>>(第一个,T类型)中只有一个参数。例如,我期望下面的内容被打破(而且它确实):

 // find people who are their own boss 
     var pair = Parse<Foo>(entity => entity.Id == entity.ManagerId); 

重新复杂性;有一个很多案件可以解析没有编译;我使用“尝试并回退编译”策略。参见EvaluateTryEvaluate方法,here

+0

嘿马克,谢谢你的回答。这正是我遇到问题的那种表达方式。在给定的情况下,您的TryEvaluate也会失败(请参阅编辑的问题)。当我回到Compile时,我遇到了上述异常。 – 2010-05-01 11:33:16

+0

@Moshe - 好的,它会的。除非你同时传递实例,否则你*不能*做你正在问的东西。而且你这样做,只需将它编译为'Func '并调用在实例中传递的委托。你会期望它从哪里获得价值? – 2010-05-01 19:09:50