Svi*_*ish 17 c# lambda expression exception expression-trees
好的,这是一个棘手的问题.希望这里有一位表达大师能够发现我在这里做错了什么,因为我只是没有得到它.
我正在构建用于过滤查询的表达式.为了简化这个过程,我有几个Expression<Func<T, bool>>扩展方法,使我的代码更清晰,到目前为止,他们已经很好地工作.我已经为所有人编写了测试,除了一个,我今天写了一个.并且该测试完全失败ArgumentException,具有长堆栈跟踪.我只是不明白.特别是因为我在查询中成功使用了该方法一段时间了!
无论如何,这是运行测试时得到的堆栈跟踪:
failed: System.ArgumentException : An item with the same key has already been added.
at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
at System.Linq.Expressions.ExpressionCompiler.PrepareInitLocal(ILGenerator gen, ParameterExpression p)
at System.Linq.Expressions.ExpressionCompiler.GenerateInvoke(ILGenerator gen, InvocationExpression invoke, StackType ask)
at System.Linq.Expressions.ExpressionCompiler.Generate(ILGenerator gen, Expression node, StackType ask)
at System.Linq.Expressions.ExpressionCompiler.GenerateBinary(ILGenerator gen, BinaryExpression b, StackType ask)
at System.Linq.Expressions.ExpressionCompiler.Generate(ILGenerator gen, Expression node, StackType ask)
at System.Linq.Expressions.ExpressionCompiler.GenerateUnliftedAndAlso(ILGenerator gen, BinaryExpression b)
at System.Linq.Expressions.ExpressionCompiler.GenerateAndAlso(ILGenerator gen, BinaryExpression b, StackType ask)
at System.Linq.Expressions.ExpressionCompiler.GenerateBinary(ILGenerator gen, BinaryExpression b, StackType ask)
at System.Linq.Expressions.ExpressionCompiler.Generate(ILGenerator gen, Expression node, StackType ask)
at System.Linq.Expressions.ExpressionCompiler.GenerateUnliftedOrElse(ILGenerator gen, BinaryExpression b)
at System.Linq.Expressions.ExpressionCompiler.GenerateOrElse(ILGenerator gen, BinaryExpression b, StackType ask)
at System.Linq.Expressions.ExpressionCompiler.GenerateBinary(ILGenerator gen, BinaryExpression b, StackType ask)
at System.Linq.Expressions.ExpressionCompiler.Generate(ILGenerator gen, Expression node, StackType ask)
at System.Linq.Expressions.ExpressionCompiler.GenerateInvoke(ILGenerator gen, InvocationExpression invoke, StackType ask)
at System.Linq.Expressions.ExpressionCompiler.Generate(ILGenerator gen, Expression node, StackType ask)
at System.Linq.Expressions.ExpressionCompiler.GenerateUnliftedAndAlso(ILGenerator gen, BinaryExpression b)
at System.Linq.Expressions.ExpressionCompiler.GenerateAndAlso(ILGenerator gen, BinaryExpression b, StackType ask)
at System.Linq.Expressions.ExpressionCompiler.GenerateBinary(ILGenerator gen, BinaryExpression b, StackType ask)
at System.Linq.Expressions.ExpressionCompiler.Generate(ILGenerator gen, Expression node, StackType ask)
at System.Linq.Expressions.ExpressionCompiler.GenerateLambda(LambdaExpression lambda)
at System.Linq.Expressions.ExpressionCompiler.CompileDynamicLambda(LambdaExpression lambda)
at System.Linq.Expressions.Expression`1.Compile()
PredicateTests.cs(257,0): at Namespace.ExpressionExtensionsTests.WhereWithin_CollectionIsFilteredAsExpected()
Run Code Online (Sandbox Code Playgroud)
测试本身如下所示,它在Compile语句中失败:
[Test]
public void WhereWithin_CollectionIsFilteredAsExpected()
{
var range = new[] { Range.Create(2, 7), Range.Create(15, 18) };
var predicate = Predicate
.Create<int>(x => x % 2 == 0)
.AndWithin(range, x => x)
.Compile();
var actual = Enumerable.Range(0, 20)
.Where(predicate)
.ToArray();
Assert.That(actual, Is.EqualTo(new[] { 2, 4, 6, 16, 18 }));
}
Run Code Online (Sandbox Code Playgroud)
我只是不明白错误信息.我认为这可能与我总是x用作参数名称的事实有关,但是当我试图交换它们时似乎没有帮助.让我更奇怪的是,我已经在更大的Linq2Sql查询中使用了这个确切的方法已经有一段时间了,并且它们总是很好地工作.所以在我的测试中,我试图不编译表达式并使用,AsQueryable所以我可以在它上面使用它.但这只是在异常上发生异常ToArray.这里发生了什么?我怎样才能解决这个问题?
您可以在以下行的zip文件中找到有问题且烦人的代码:
注意:我在这里发布了一些相关代码,但经过一些评论之后,我决定将代码提取到自己的项目中,这样可以更清楚地显示异常.更重要的是,可以运行,编译和调试.
更新:使用@Mark的一些建议进一步简化了示例项目.像删除范围类,而只是硬编码单个恒定范围.还添加了另一个示例,其中使用完全相同的方法实际上工作正常 因此,使用AndWithin方法会使应用程序崩溃,而使用WhereWithin方法实际上可以正常工作.我觉得几乎无能为力!
这不是答案,但我希望它能帮助有人找到答案。我进一步简化了代码,使其只是一个文件,但仍然以同样的方式失败。我已重命名变量,以便“x”不会使用两次。我删除了 Range 类,并将其替换为硬编码常量 0 和 1。
using System;
using System.Linq;
using System.Linq.Expressions;
class Program
{
static Expression<Func<int, bool>> And(Expression<Func<int, bool>> first,
Expression<Func<int, bool>> second)
{
var x = Expression.Parameter(typeof(int), "x");
var body = Expression.AndAlso(Expression.Invoke(first, x), Expression.Invoke(second, x));
return Expression.Lambda<Func<int, bool>>(body, x);
}
static Expression<Func<int, bool>> GetPredicateFor(Expression<Func<int, int>> selector)
{
var param = Expression.Parameter(typeof(int), "y");
var member = Expression.Invoke(selector, param);
Expression body =
Expression.AndAlso(
Expression.GreaterThanOrEqual(member, Expression.Constant(0, typeof(int))),
Expression.LessThanOrEqual(member, Expression.Constant(1, typeof(int))));
return Expression.Lambda<Func<int, bool>>(body, param);
}
static void Main()
{
Expression<Func<int, bool>> predicate = a => true;
predicate = And(predicate, GetPredicateFor(b => b)); // Comment out this line and it will run without error
var z = predicate.Compile();
}
}
Run Code Online (Sandbox Code Playgroud)
该表达式在调试器中如下所示:
x => (Invoke(a => True,x) && Invoke(y => ((Invoke(b => b,y) >= 0) && (Invoke(b => b,y) <= 1)),x))
Run Code Online (Sandbox Code Playgroud)
更新:我已经将其简化为最简单的,同时仍然抛出相同的异常:
using System;
using System.Linq;
using System.Linq.Expressions;
class Program
{
static void Main()
{
Expression<Func<int, bool>> selector = b => true;
ParameterExpression param = Expression.Parameter(typeof(int), "y");
InvocationExpression member = Expression.Invoke(selector, param);
Expression body = Expression.AndAlso(member, member);
Expression<Func<int, bool>> predicate = Expression.Lambda<Func<int, bool>>(body, param);
var z = predicate.Compile();
}
}
Run Code Online (Sandbox Code Playgroud)