【发布时间】:2011-01-07 12:14:08
【问题描述】:
好的,这是一个棘手的问题。希望这里有一位表达大师可以发现我在这里做错了什么,因为我只是不明白。
我正在构建用于过滤查询的表达式。为了简化这个过程,我有几个Expression<Func<T, bool>> 扩展方法可以让我的代码更简洁,并且到目前为止它们运行良好。我已经为所有这些都写了测试,除了一个,我今天写了一个。该测试完全失败,ArgumentException 带有 long 堆栈跟踪。我就是不明白。特别是因为我在查询中成功地使用了该方法一段时间!
无论如何,这是我在运行测试时得到的堆栈跟踪:
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()
测试本身如下所示,它在 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 }));
}
我只是不明白错误信息。我认为这可能与我总是使用 x 作为参数名称这一事实有关,但是当我尝试交换它们时似乎没有帮助。对我来说更奇怪的是,我已经在更大的 Linq2Sql 查询中使用这种确切的方法一段时间了,而且它们一直运行良好。所以在我的测试中,我尝试不编译表达式并使用AsQueryable,所以我可以在上面使用它。但这只是在ToArray 上发生了异常。这里发生了什么?我该如何解决这个问题?
您可以在 zip 文件中的以下行中找到令人讨厌和烦人的代码:
注意:我已经在这里发布了一些相关的代码,但是在一些 cmet 之后,我决定将代码提取到它自己的项目中,这样可以更清楚地显示异常。更重要的是,它可以运行、编译和调试。
更新:利用@Mark 的一些建议进一步简化了示例项目。就像删除范围类,而只是硬编码单个常量范围。还添加了另一个示例,其中使用完全相同的方法实际上可以正常工作。因此,使用 AndWithin 方法会使应用程序崩溃,而使用 WhereWithin 方法实际上可以正常工作。我觉得很无知!
【问题讨论】:
-
Range<TValue>是你自己写的类吗? -
@Mark:是的,它主要是一个有开始和结束的类。虽然我有一系列的扩展方法,它有 equals 被覆盖等等。但在这种情况下,这并不重要。这是一个非常简单的类:)
-
作为注释,System.Predicate 已经存在,所以命名有些混乱。 msdn.microsoft.com/en-us/library/bfcke1bz.aspx
-
@recursive:我知道,但想不出更好的。而且因为我从来没有真正使用过那个谓词委托......是的......:p
-
@Mark:好吧,我不这样做就无法入睡。用最少的代码制作了一个小项目来犯错误。好吧,可能会更少,但是是的。 编辑问题
标签: c# exception lambda expression expression-trees