c# - ultimo - La consulta de Linq incorporada en el bucle foreach siempre toma el valor del parámetro de la última iteración
que hace do en c++ (3)
Tengo una lista que contiene varias palabras clave. Los busqué construyendo mi consulta linq con ellos de esa manera (reducida para eliminar el ruido del código):
List<string> keys = FillKeys()
foreach (string key in keys){
q = q.Where(c => c.Company.Name.Contains(key));
}
Cuando hago que mis teclas contengan 2 claves que devuelven los resultados por separado, pero nunca pueden ocurrir juntas (cada elemento en q es "xyz" o "123", nunca "123" Y "xyz"), sigo obteniendo resultados. El resultado es entonces el mismo que el último hilo al que llegó.
He echado un vistazo a la consulta de linq y parece que crea el sql correcto, pero reemplaza a @ p1 AND @ p2 por el mismo valor (último valor).
¿Qué estoy haciendo mal?
Posiblemente un problema variable capturado; intente agregar:
List<string> keys = FillKeys()
foreach (string key in keys){
string tmp = key;
q = q.Where(c => c.Company.Name.Contains(tmp));
}
se ha corregido en C # 5.0, y el ejemplo anterior en C # 5.0 funciona pero falla en las versiones anteriores de C #.
Pero ten cuidado, no se trata de un bucle for
static void Main()
{
IEnumerable<char> query = "aaa bbb ccc";
string lettersToRemove = "ab";
Console.WriteLine("/nOK with foreach:");
foreach (var item in lettersToRemove)
{
query = query.Where(c => c != item);
}
foreach (char c in query) Console.Write(c);
//OK:
Console.WriteLine("/nOK with foreach and local temp variable:");
query = "aaa bbb ccc";
foreach (var item in lettersToRemove)
{
var tmp = item;
query = query.Where(c => c != tmp);
}
foreach (char c in query) Console.Write(c);
/*
An IndexOutOfRangeException is thrown because:
firstly compiler iterates the for loop treating i as an outsite declared variable
when the query is finnaly invoked the same variable of i is captured (lettersToRemove[i] equals 3) which generates IndexOutOfRangeException
The following program writes aaa ccc instead of writing ccc:
Each iteration gets the same variable="C", i (last one frome abc).
*/
//Console.WriteLine("/nNOK with for loop and without temp variable:");
//query = "aaa bbb ccc";
//for (int i = 0; i < lettersToRemove.Length; i++)
//{
// query = query.Where(c => c != lettersToRemove[i]);
//}
//foreach (char c in query) Console.Write(c);
/*
OK
The solution is to assign the iteration variable to a local variable scoped inside the loop
This causes the closure to capture a different variable on each iteration.
*/
Console.WriteLine("/nOK with for loop and with temp variable:");
query = "aaa bbb ccc";
for (int i = 0; i < lettersToRemove.Length; i++)
{
var tmp = lettersToRemove[i];
query = query.Where(c => c != tmp);
}
foreach (char c in query) Console.Write(c);
}
Está reutilizando la misma variable ( key
) en su expresión lambda.
Vea mi artículo sobre métodos anónimos para más detalles, y también hay una serie de preguntas SO relacionadas:
- Error LINQ to SQL (o característica muy extraña) ...
- Variables locales con delegados
- C # captura la variable en un bucle
- C # gotcha respuesta
- Construir una consulta LINQ mediante programación sin que las variables locales me engañen
La solución simple es copiar la variable primero:
List<string> keys = FillKeys()
foreach (string key in keys){
string copy = key;
q = q.Where(c => c.Company.Name.Contains(copy));
}