关于“可能的多重枚举”的可枚举的所有*使用的Resharper警告

时间:2012-12-03 15:53:30

标签: c# linq resharper ienumerable enumeration

我从Reshaper收到“Possible Multiple Enumeration of IEnumerable”警告。如何处理它已经asked in another SO question。我的问题稍微具体一点,关于警告弹出的各个地方。

我想知道Resharper是否正确地给我这个警告。我主要关注的是警告发生在下面users变量的所有实例上,代码中标有“//Warn”。

我的代码正在收集要在网格中显示在网页上的信息。我正在使用服务器端分页,因为整个数据集可能长达数十或数十万行。我尽可能地评论了代码。

请再次告诉我此代码是否容易受到多次枚举的影响。我的目标是在调用ToList()之前执行我对数据的过滤和排序。这是正确的方法吗?

private List<UserRow> GetUserRows(UserFilter filter, int start, int limit,
                                  string sort, SortDirection dir, out int count)
{
    count = 0;

    // LINQ applies filter to Users object
    var users = (
            from u in _userManager.Users
            where filter.Check(u)
            select new UserRow
                        {
                            UserID = u.UserID,
                            FirstName = u.FirstName,
                            LastName = u.LastName,
                            // etc.
                        }
        );

    // LINQ orders by given sort
    if (!String.IsNullOrEmpty(sort))
    {
        if (sort == "UserID" && dir == SortDirection.ASC)
            users = users.OrderBy(u => u.UserID); //Warn
        else if (sort == "UserID" && dir == SortDirection.DESC)
            users = users.OrderByDescending(u => u.UserID); //Warn
        else if (sort == "FirstName" && dir == SortDirection.ASC)
            users = users.OrderBy(u => u.FirstName); //Warn
        else if (sort == "FirstName" && dir == SortDirection.DESC)
            users = users.OrderByDescending(u => u.FirstName); //Warn
        else if (sort == "LastName" && dir == SortDirection.ASC)
            users = users.OrderBy(u => u.LastName); //Warn
        else if (sort == "LastName" && dir == SortDirection.DESC)
            users = users.OrderByDescending(u => u.LastName); //Warn
        // etc.
    }
    else
    {
        users = users.Reverse(); //Warn
    }

    // Output variable
    count = users.Count(); //Warn

    // Guard case - shouldn't trigger
    if (limit == -1 || start == -1)
        return users.ToList(); //Warn

    // Pagination and ToList()
    return users.Skip((start / limit) * limit).Take(limit).ToList(); //Warn
}

2 个答案:

答案 0 :(得分:4)

是的,ReSharper是对的:count = users.Count();无条件枚举,如果limitstart不是否定1,则ToList将枚举再次users

看起来,一旦ReSharper决定某些内容有被多次枚举的风险,它会使用多个枚举警告标记对所讨论项目的每一个引用,即使它不是负责多次枚举的代码。这就是为什么你看到这么多行的警告。

更好的方法是添加单独的调用来设置计数。您可以在单独的声明中预先完成,如下所示:

count = _userManager.Users.Count(u => filter.Check(u));

通过这种方式,您可以将users置于其预先列举的状态,直到最后一次调用ToList

答案 1 :(得分:1)

希望通过调用Count生成您的警告,limit == -1 || start == -1会运行额外的查询。

如果ToList您可以进行count来电,然后从那里获取return ,但在一般情况下,您无能为力做 - 你 做两个查询,一个用于完整计数,一个用于项目的子集。

我很想知道修理特殊情况是否会导致警告消失。


编辑:由于这是LINQ到对象,您可以将foreach行替换为整个集合中的(select new UserRow)循环计算它们,但也可以构建受限制的跳过/动态获取子列表,因此只迭代一次。

您还可以在此foreach循环中,在您的特殊情况ToList之前预测var users = _userManager.Users.Where(u => filter.Check(u)); // Sort as above List<UserRow> rtn; if (limit == -1 || start == -1) { rtn = users.Select(u => new UserRow { UserID = u.UserID, ... }).ToList(); count = rtn.Length; } else { int takeFrom = (start / limit) * limit; int forgetFrom = takeFrom + limit; count = 0; rtn = new List<UserRow>(); foreach(var u in users) { if (count >= takeFrom && count < forgetFrom) rtn.Add(new UserRow { UserID = u.UserID, ... }); count++; } } return rtn; ,而不是预测整个集合,然后可能放弃您的大多数对象。

{{1}}