Я пытаюсь найти хороший способ кумулятивно применить до 5 Func к одному и тому же IEnumerable. Вот что я придумал:
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;
}
Я думал, что они будут применяться кумулятивно, однако из результатов я вижу, что на самом деле применяется только последний (DepartmentFilter)
Существует 2^4 возможных комбинации, поэтому грубая сила if/elses не будет работать (я хочу, чтобы И использовал конкретную лямбду только тогда, когда соответствующий ключ присутствует в словаре.)
РЕДАКТИРОВАТЬ: Вот решение, которое я принял, но оно вызывает исключение StackOverflowException при его оценке. Кто-нибудь видит, почему?
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;
}
РЕДАКТИРОВАТЬ: Вот очень хорошее объяснение того, почему это привело к исключению StackOverflowException, от друга и наставника Криса Флатера:
Важным моментом для понимания того, почему возникает бесконечная рекурсия, является понимание того, когда разрешаются символы в лямбда-выражении (т.е. во время выполнения, а не во время выполнения). определение).
Возьмем этот упрощенный пример:
Func<int, int> demo = (x) => x * 2;
Func<int, int> demo2 = (y) => demo(y) + 1;
demo = demo2;
int count = demo(1);
Если бы это было разрешено статически при определении, это будет работать и будет таким же, как:
Func<int, int> demo2 = (y) => (y * 2) + 1;
Int count = demo2(1);
Но на самом деле он не пытается выяснить, что делает демо, встроенное в demo2, до времени выполнения – в это время demo2 был переопределен как demo. По сути, теперь код выглядит следующим образом:
Func<int, int> demo2 = (y) => demo2(y) + 1;
Int count = demo2(1);