繁体   English   中英

可枚举<t> .Count() 返回 0</t>

[英]IEnumerable<T>.Count() returns 0

我有一个IEnumerable类型的变量,如果我在 foreach 循环之前对其调用Count()方法,那么它会返回正确的计数,但在 foreach 循环之后它会返回 0。这是为什么呢?

[更新]

根据给定的答案,我发现我的IEnumerable是一种一次性的东西。 所以我附上了我的代码,因为我已经将它转换为列表并作为IEnumerable返回。 那么我哪里做错了?

public async Task<IEnumerable<WorkItem>> Get(int[] workItemIds)
{
    return await context.WorkItems
                        .Where(it => workItemIds.Contains(it.Id))
                        .ToListAsync();
}

private async Task<int> ApproveOrRejectWorkItems(IEnumerable<WorkItem> workItems, int status)
{
    // var workItemsToBeUpdated = workItems.Count();
    workItems = workItems.Where(it => it.StatusId == (int)WorkItemStatus.Submitted);
    foreach (var workItem in workItems)
    {
        workItem.StatusId = status;
    }

    // here value becomes 0

    await _unitOfWork.WorkItemRepository.Update(workItems);

    return workItems.Count();
}

您很可能正在处理以下两种情况之一:

枚举之间的外部环境变化

请考虑以下情况:

var badRecords = repository.GetBadRecords(); //returns IEnumerable<T>
if(badRecords.Count() > n) 
{
  repository.DeleteBadRecords();
}

foreach( var badRecords in badRecords ) 
// This enumeration goes to the db again and selects 0 records because we just deleted them. 
{ 
  Log(badRecord);
};

解决办法是.ToList()

一次性发电机

这很相似但略有不同,我们处理的代码在设计上只允许一次迭代。

public static IEnumerable<int> GetAllNumbers(List<int> availableNumbers) {
    while(availableNumbers.Count > 0) 
    {
        var x = availableNumbers[0];
        availableNumbers.RemoveAt(0);
        yield return x;
    }
}

static void Main(string[] args)
{
    var numbers = GetAllNumbers(new List<int>{1,2,3});
    Console.WriteLine(numbers.Count()); // 3
    Console.WriteLine(numbers.Count()); // 0

    numbers = GetAllNumbers(new List<int>{1,2,3}).ToList();
    Console.WriteLine(numbers.Count()); // 3
    Console.WriteLine(numbers.Count()); // 3
}

Resharper 的Possible multiple enumeration of IEnumerable警告

顺便提一句。 Resharper 对此有专门的警告: Code Inspection: Possible multiple enumeration of IEnumerable

感谢您澄清您是在Get()方法中具体化列表后过滤列表。

您的问题是 LINQ 是一个视图。 因此,如果您将IEnumerable迭代两次,它将 go 遍历源项两次,对源项应用任何过滤器、投影等。 这意味着通过更改源项目,可枚举将在您第二次迭代时产生不同的项目,因为这些项目不再与过滤器匹配。

我建议您将方法修改为:

private async Task<int> ApproveOrRejectWorkItems(IEnumerable<WorkItem> workItems, int status)
{
    var workItemsToBeUpdated = workItems.Count();

    foreach (var workItem in workItems.Where(it => it.StatusId == (int)WorkItemStatus.Submitted))
    {
        workItem.StatusId = status;
    }

    await _unitOfWork.WorkItemRepository.Update(workItems);

    return workItems.Count();
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM