3

我正在尝试使用 EF 5 将多个搜索条件应用于结果集(在本例中,用于图书馆目录搜索)。以下是相关代码:

public IQueryable<LibraryResource> GetSearchResults(string SearchCriteria, int? limit = null)
    {
        List<string> criteria = SearchCriteria.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).ToList();
        IQueryable<LibraryResource> allResults = context.LibraryResources.Include("Type").Where(r => r.AuditInfo.DeletedAt == null);
        foreach (string criterion in criteria)
        {
            allResults = allResults.Where(r => (r.Title.Contains(criterion) || r.Keywords.Contains(criterion) || r.Author.Contains(criterion) || r.Comments.Contains(criterion)));
        }
        allResults = allResults.OrderBy(r => r.Title);
        if (limit.HasValue) allResults = allResults.Take(limit.Value);
        return allResults;
    }

示例 SearchCriteria = "历史时代"

出于某种原因,只有最后一个标准被应用。例如,在上面的示例中,所有在标题、作者、关键字和评论中带有“时代”的书籍都被返回,而没有按“历史”进行过滤。我单步执行了代码,循环执行了两次,每次都使用适当的标准。你能看到我看不到的东西吗?谢谢!

4

1 回答 1

5

您已成为修改封闭变量值的受害者。

将代码更改为:

foreach (string criterion in criteria)
{
    var crit = criterion;
    allResults = allResults.Where(/* use crit here, not criterion */);
}

这里的问题是,当您构建查询时,您的过滤表达式关闭变量criterion,实际上是在评估查询的点将其拉入范围。但是,那时criterion只有一个值(它碰巧循环的最后一个值),所以除了最后一个过滤器之外的所有过滤器实际上都会变成最后一个的副本。

在表达式中创建本地副本criterion并引用它可以纠正问题,因为每次crit都是不同的本地变量,其生命周期不会从循环的一次迭代延伸到下一次迭代。

有关更多详细信息,您可能想阅读C# 在 foreach 中重用变量是否有原因?,其中还提到 C# 5.0 将采取适用于这种情况的重大更改:循环变量的生命周期criterion将发生变化,使此代码在没有额外本地的情况下正常工作。

于 2013-02-04T21:06:28.257 回答