在我搜索表达式解析器时,我找到了Dynamic LINQ API。我想使用此API让最终用户指定一些验证业务对象的标准。
所以我第一次尝试使用该库成功进行以下单元测试
var x = Expression.Parameter(typeof(int), "x");
var list = Expression.Parameter(typeof(List<int>), "list");
var e = DynamicExpression.ParseLambda(new[] { x, list }, null, "list.Any(it == x)");
var compiledExpression = e.Compile();
var myList = new List<int> { 24, 46, 67, 78 };
Assert.AreEqual(false, compiledExpression.DynamicInvoke(2, myList));
Assert.AreEqual(true, compiledExpression.DynamicInvoke(24, myList));
但是我希望有一个稍微复杂的语法,因为我想改变这个
list.Any(it == x) // OK
到
list.Any(i => i == x) // Raises error: No property or field 'i' exists in type 'int'
然而,第二种语法允许我嵌套lambda(这是我的最终目标),如下所示:
list1.All(i => list2.Any(j => j == i))
任何人都知道如何调整Dynamic.cs以支持此语法?
答案 0 :(得分:2)
经过几个小时的调试后,我自己找到了解决方案。
以下单元测试现在成功:
var list1 = Expression.Parameter(typeof(List<int>), "list1");
var list2 = Expression.Parameter(typeof(List<int>), "list2");
var e = DynamicExpression.ParseLambda(new[] { list1, list2 }, null, "list2.All(i => list1.Any(j => j == i))");
var compiledExpression = e.Compile();
var myList1 = new List<int> { 24, 46, 67, 78 };
var myList2 = new List<int> { 46 };
var myList3 = new List<int> { 8 };
Assert.AreEqual(true, compiledExpression.DynamicInvoke(myList1, myList2));
Assert.AreEqual(false, compiledExpression.DynamicInvoke(myList1, myList3));
我已应用于示例Dynamic.cs文件的更改:
1)使用成员'Lambda'
扩展enum TokenId2)将一个名为internals的IDictionary添加到ExpressionParser类中。在ExpressionParser构造函数
中初始化它3)替换(从第971行开始)
if (symbols.TryGetValue(token.text, out value) ||
externals != null && externals.TryGetValue(token.text, out value)) {
与
if (symbols.TryGetValue(token.text, out value) ||
externals != null && externals.TryGetValue(token.text, out value) ||
internals.TryGetValue(token.text, out value)) {
4)替换(从第1151行开始)
if (member == null)
throw ParseError(errorPos, Res.UnknownPropertyOrField,
id, GetTypeName(type));
与
if (member == null)
{
if(token.id == TokenId.Lambda && it.Type == type)
{
// This might be an internal variable for use within a lambda expression, so store it as such
internals.Add(id, it);
NextToken();
var right = ParseExpression();
return right;
}
else
{
throw ParseError(errorPos, Res.UnknownPropertyOrField,
id, GetTypeName(type));
}
}
5)替换(从第1838行开始)
case '=':
NextChar();
if (ch == '=') {
NextChar();
t = TokenId.DoubleEqual;
}
else {
t = TokenId.Equal;
}
break;
与
case '=':
NextChar();
if (ch == '=') {
NextChar();
t = TokenId.DoubleEqual;
}
else if(ch == '>')
{
NextChar();
t = TokenId.Lambda;
}
else {
t = TokenId.Equal;
}
break;