foreach或开关乱搞linq查询?

时间:2011-11-28 17:40:18

标签: linq

尝试构建一个查询以按以下方式过滤数据的工作正常,返回过滤的所有过滤器都在FilterNamesAndValues参数中。

GetAllUsersFiltered(..., Dictionary<string,string> FilterNamesAndValues)
{
    ....

    List<DataContracts.IUser> lstUsers = new List<DataContracts.IUser>();
    ....

    var query = from u in lstUsers select u;

    string firstName = string.Empty;
    FilterNamesAndValues.TryGetValue("FirstName", out firstName);
    query = query.Where(u => u.FirstName == firstName);

    string company = string.Empty;
    FilterNamesAndValues.TryGetValue("Company", out company);
    query = query.Where(u => u.CompanyName == company);

    ....
    return query.ToList();
}

但是下面的例子不起作用,我看不出原因:

GetAllUsersFiltered(..., Dictionary<string,string> FilterNamesAndValues)
{

    ....

    List<DataContracts.IUser> lstUsers = new List<DataContracts.IUser>();

    ....

    var query = from u in lstUsers select u;

    foreach (KeyValuePair<string, string> kv in FilterNamesAndValues)
        {
            if (kv.Value != null)
            {
                switch (kv.Key)
                {
                    case "FirstName":
                        query = query.Where(u => u.FirstName == kv.Value);
                        break;

                    case "Company":
                        query = query.Where(u => u.CompanyName == kv.Value);
                        break;

                }
            }
        }

        return query.ToList();
}

在应用程序遇到第一个switch case之后,我可以执行query.ToList()并在那里看到一行。但是当执行绕过第二个过滤器的循环时,query.ToList()什么都不返回。查询不会像第一个示例中那样连续过滤,更糟糕的是,过滤条件实际上已经丢失。对此可能有一个明显的解释,但现在我看不到它。

1 个答案:

答案 0 :(得分:4)

问题是你在foreach中关闭kv,但查询是使用延迟执行执行的。这会导致它关闭错误的值。有关正在发生的事情的详细信息,我建议Eric Lippert的帖子标题为“Closing over the loop variable considered harmful”。

您可以通过临时解决此问题:

foreach (KeyValuePair<string, string> kvOriginal in FilterNamesAndValues)
    {
        // Make a temporary in the correct scope!
        KeyValuePair<string, string> kv = kvOriginal;
        if (kv.Value != null)
        {
            switch (kv.Key)
            {
                case "FirstName":
                    query = query.Where(u => u.FirstName == kv.Value);
                    break;

                case "Company":
                    query = query.Where(u => u.CompanyName == kv.Value);
                    break;

            }
        }
    }