这如何不会导致 IEnumerable 的多个枚举

本文关键字:枚举 IEnumerable 何不会 | 更新日期: 2023-09-27 18:36:17

我最初将参数类型设置为ICollection,因为我认为我会遇到IEnumerable的多个枚举的问题。 但是,Resharper 建议我可以将参数类型转换为 IEnumerable。 我最终做了一个测试来仔细检查,它似乎工作正常:

    private static void Main(string[] args)
    {
        var nums = GetNums();
        MultipleEnumerations(nums);
        Console.ReadLine();
    }
    private static void MultipleEnumerations(IEnumerable<int> nums)
    {
        var otherNums = new List<int> {1, 2, 3, 4, 5};
        var filtered = otherNums.Where(num => nums.Contains(num));
        foreach (var num in filtered)
        {
            Console.WriteLine(num);
        }
    }
    private static IEnumerable<int> GetNums()
    {
        yield return 4;
        yield return 2;
    }

这如何不会导致 IEnumerable 的多个枚举?

这如何不会导致 IEnumerable 的多个枚举

这确实会导致可枚举项的多个枚举。

如果我将您的代码更改为以下内容:

private static void MultipleEnumerations(IEnumerable<int> nums)
{
    var otherNums = new List<int> { 1, 2, 3, 4, 5 };
    var filtered = otherNums.Where(num =>
    {
        Console.WriteLine("{0}?", num);
        return nums.Contains(num);
    });
    foreach (var num in filtered)
    {
        Console.WriteLine(num);
    }
}
private static IEnumerable<int> GetNums()
{
    Console.WriteLine("4!");
    yield return 4;
    Console.WriteLine("2!");
    yield return 2;
}

。然后我可以得到以下输出:

1?4!2!2?4!2!23?4!2!4?4!45?4!2!

您可以看到,对于正在测试的每个otherNums,它每次都在运行nums(这是GetNums)。当测试4它只需要第一个nums数,但除此之外,它会完全迭代5次。

如果你想知道为什么.Whereforeach都不迭代otherNums那是因为.Where是使用延迟执行模型运行的 - 只有当你执行foreach或类似.ToList()时,它才会执行。

Resharper可能建议将参数的类型更改为IEnumerable,因为没有调用者会传递(派生自)IEnumerable以外的其他类型,Resharper建议使用最简单的类型。

ICollection 仅向派生IEnumerable添加几个属性和方法,最重要的是 Count 属性。

根据此表,对于实现ICollection的大多数类,GetEnumerator()方法具有相同的复杂性。