Estoy tratando de encontrar una buena manera de aplicar acumulativamente hasta 5 Func's al mismo IEnumerable. Esto es lo que ocurrió:Necesito && juntos un número indeterminado de Func <TEntity, bool>
private Func<SurveyUserView,bool> _getFilterLambda(IDictionary<string, string> filters)
{
Func<SurveyUserView, bool> invokeList = delegate(SurveyUserView surveyUserView)
{
return surveyUserView.deleted != "deleted";
};
if (filters.ContainsKey("RegionFilter"))
{
invokeList += delegate(SurveyUserView surveyUserView)
{
return surveyUserView.Region == filters["RegionFilter"];
};
}
if (filters.ContainsKey("LanguageFilter"))
{
invokeList += delegate(SurveyUserView surveyUserView)
{
return surveyUserView.Locale == filters["LanguageFilter"];
};
}
if (filters.ContainsKey("StatusFilter"))
{
invokeList += delegate(SurveyUserView surveyUserView)
{
return surveyUserView.Status == filters["StatusFilter"];
};
}
if (filters.ContainsKey("DepartmentFilter"))
{
invokeList += delegate(SurveyUserView surveyUserView)
{
return surveyUserView.department == filters["DepartmentFilter"];
};
}
return invokeList;
}
pensé que sería aplicarlos de manera acumulativa, sin embargo, puedo ver en los resultados que en realidad es simplemente la aplicación de la última (DepartmentFilter).
Existen 2^4 combinaciones posibles de modo que las fuerzas brutas no funcionen. (Quiero Y utilizando una lambda particular solo cuando la clave correspondiente está presente en el Diccionario.)
EDIT: Aquí está la solución que acepté, pero causa una StackOverflowException cuando se evalúa. ¿Alguien ve por qué?
private Func<SurveyUserView,bool> _getFilterLambda(IDictionary<string, string> filters)
{
Func<SurveyUserView, bool> resultFilter = (suv) => suv.deleted != "deleted";
if (filters.ContainsKey("RegionFilter"))
{
Func<SurveyUserView, bool> newFilter =
(suv) => resultFilter(suv) && suv.Region == filters["RegionFilter"];
resultFilter = newFilter;
}
if (filters.ContainsKey("LanguageFilter"))
{
Func<SurveyUserView, bool> newFilter =
(suv) => resultFilter(suv) && suv.Locale == filters["LanguageFilter"];
resultFilter = newFilter;
}
if (filters.ContainsKey("StatusFilter"))
{
Func<SurveyUserView, bool> newFilter =
(suv) => resultFilter(suv) && suv.Status == filters["StatusFilter"];
resultFilter = newFilter;
}
if (filters.ContainsKey("DepartmentFilter"))
{
Func<SurveyUserView, bool> newFilter =
(suv) => resultFilter(suv) && suv.department == filters["DepartmentFilter"];
resultFilter = newFilter;
}
return resultFilter;
}
EDIT: Aquí está el muy agradable explicación de por qué esto dio lugar a una StackOverflowException de amigo y mentor Chris Flather-
Lo importante para entender por qué se produce el bucle infinito es la comprensión de que los símbolos en una lambda se resuelve (es decir, en tiempo de ejecución y no en definición).
Tome este ejemplo simplificado:
Func<int, int> demo = (x) => x * 2;
Func<int, int> demo2 = (y) => demo(y) + 1;
demo = demo2;
int count = demo(1);
Si se resuelve de forma estática en la definición esto iba a funcionar y ser el mismo que:
Func<int, int> demo2 = (y) => (y * 2) + 1;
Int count = demo2(1);
Pero en realidad no intentar averiguar qué la demo incorporada en demo2 funciona hasta el tiempo de ejecución, en cuyo momento demo2 se ha redefinido como demo. En esencia, el código ahora se lee:
Func<int, int> demo2 = (y) => demo2(y) + 1;
Int count = demo2(1);
¡ADVERTENCIA! Esto causó una excepción de desbordamiento de pila cuando lo implementé. (Lo cual es un poco irónico. :)) La solución de Reed tiene buen sentido lógico, pero su comentario en la parte inferior (encadenando las cláusulas Where) parece ser la única manera de ir aquí. –
@TreyCarroll ¿Lo implementó de la misma manera que la anterior, utilizando una variable temporal para la nueva lambda? –
Sí. Seguí tu patrón exactamente. Recién confirmado que es arrojar SOE. –