我正在编写一个Expression Parser,以使我的API更易于重构,并且不易出错。 基本上,我希望用户编写这样的代码:
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();
}
现在,我在Compile行中得到一个InvalidOperationException(Lambda参数不在范围内)。当我用Google搜索解决方案时,我想出了类似的问题,包括手工构建表达式而不是提供所有部分,或者试图依赖具有相同名称和不同参考的参数。我认为这不是这种情况,因为我正在重复使用给定的表达式。
修改
这是非工作方案之一:
ExpressionParser.Parse(entity =&gt; entity.InternalClass.Id == entity.Id);
如果有人能给我一些指示,我将不胜感激。 谢谢。
答案 0 :(得分:1)
带有常量的版本与发布的代码一起正常工作。你能说明一个不起作用的例子吗?
当您看到这一点时,表示您的Right
正在尝试使用参数; Expression<Func<T, bool>>
中只有一个参数(第一个参数类型为T
)。例如,我希望以下内容会破坏(并且确实如此):
// find people who are their own boss
var pair = Parse<Foo>(entity => entity.Id == entity.ManagerId);
复杂性;有一个 lot 的案例可以在没有编译的情况下解析;我使用“尝试它并回退到编译”策略。请参阅Evaluate
和TryEvaluate
方法,here。