需要和&&一起使用不确定数量的Func <TEntity,bool>

Tre*_*oll 6 c# lambda delegates

我正试图找到一个好方法,累积应用最多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;
}
Run Code Online (Sandbox Code Playgroud)

我认为它会以累积方式应用这些,但是,我可以从结果中看出它实际上只是应用了最后一个(DepartmentFilter).

有2 ^ 4种可能的组合,所以如果/ elses不起作用的话.(我希望仅在字典中存在相应的键时才使用特定的lambda.)

编辑:这是我接受的解决方案,但它在评估时会导致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;
    }
Run Code Online (Sandbox Code Playgroud)

编辑:这是非常好的解释为什么这导致朋友和导师Chris Flather的StackOverflowException-

理解为什么无限递归发生的重要一点是理解lambda中的符号何时被解析(即在运行时而不是在定义时).

举个简单的例子:

Func<int, int> demo = (x) => x * 2;
Func<int, int> demo2 = (y) => demo(y) + 1;
demo = demo2;
int count = demo(1);
Run Code Online (Sandbox Code Playgroud)

如果它在定义时被静态解析,那么它将起作用并且与以下相同:

Func<int, int> demo2 = (y) => (y * 2) + 1;
Int count = demo2(1);
Run Code Online (Sandbox Code Playgroud)

但它实际上并没有试图弄清楚demo2中嵌入的演示直到运行时 - 此时demo2已重新定义为演示.基本上代码现在是:

Func<int, int> demo2 = (y) => demo2(y) + 1;
Int count = demo2(1);
Run Code Online (Sandbox Code Playgroud)

Ree*_*sey 4

您可以构建新的委托,将现有委托与 AND 条件结合使用,而不是尝试以这种方式组合委托:

Func<SurveyUserView, bool> resultFilter = (suv) => true;

if (filters.ContainsKey("RegionFilter"))
{
    var tmpFilter = resultFilter;
    // Create a new Func based on the old + new condition
    resultFilter = (suv) => tmpFilter(suv) && suv.Region == filters["RegionFilter"];
}

if (filters.ContainsKey("LanguageFilter"))
{
   // Same as above...

//... Continue, then:

return resultFilter;
Run Code Online (Sandbox Code Playgroud)

IQueryable<SurveyUserView>话虽这么说,将原始的or传递IEnumerable<SurveyUserView>到此方法中可能更容易,只需.Where直接添加子句即可进行过滤。然后,您可以返回最终查询而不执行它,并添加过滤器。