C #: um item com a mesma chave já foi adicionado ao compilar expressão
Ok, aqui está uma questão complicada. Espero que haja uma expressão guru aqui que possa identificar o que estou fazendo de errado aqui, porque simplesmente não estou entendendo.
Estou construindo expressões que uso para filtrar consultas. Para facilitar esse processo, tenho algumasExpression<Func<T, bool>>
métodos de extensão que tornam meu código mais limpo e até agora eles têm funcionado bem. Eu escrevi testes para todos eles, exceto um, que escrevi para hoje. E esse teste falha completamente com umArgumentException
com umlongo rastreamento de pilha. E eu simplesmente não entendo. Especialmente desde que tenho usado esse método há algum tempo com êxito em minhas consultas!
De qualquer forma, aqui está o rastreamento de pilha que recebo ao executar o teste:
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()
O teste em si se parece com o seguinte, e falha na instrução 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 }));
}
Eu simplesmente não entendo a mensagem de erro. Eu pensei que isso poderia ter a ver com o fato de eu sempre usarx
como o nome do parâmetro, mas não pareceu ajudar quando tentei trocá-los. O que torna ainda mais estranho para mim é que eu já uso esse método exato há um tempo em consultas Linq2Sql maiores e elas sempre funcionaram bem. Então, no meu teste, tentei não compilar a expressão e usarAsQueryable
então eu poderia usá-lo nisso. Mas isso apenas fez a exceção ocorrer noToArray
em vez de. O que está acontecendo aqui? Como posso consertar isso?
Você pode encontrar o código ofensivo e irritante no arquivo zip abaixo da linha:
Nota: Eu publiquei alguns dos códigos relacionados aqui, mas depois de alguns comentários, decidi extrair o código em seu próprio projeto, que mostra a exceção mais claramente. E mais importante, isso pode ser executado, compilado e depurado.
ExpressionCuriosity.zipAtualizar: Simplificou o projeto de exemplo ainda mais com algumas das sugestões do @Mark. Como remover a classe de intervalo e, em vez disso, apenas codificar permanentemente um intervalo constante. Também foi adicionado outro exemplo em que o uso exato do mesmo método realmente funciona bem. Portanto, o uso do método AndWithin causa uma falha no aplicativo, enquanto o método WhereWithin realmente funciona bem. Eu me sinto praticamente sem noção!
ExpressionCuriosity.zip (Atualizada)