简体   繁体   中英

How does this not lead to multiple enumerations of an IEnumerable?

I originally set my parameter type to be ICollection because I thought I would run into issues with multiple enumerations of an IEnumerable. However, Resharper suggested that I can convert the parameter type to be an IEnumerable. I ended up making a test to double check and it seems to work fine:

    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;
    }

How does this not lead to multiple enumerations of an IEnumerable?

This does lead to multiple enumerations of an enumerable.

If I change your code to this:

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;
}

...then I can get the following output:

1?
4!
2!
2?
4!
2!
2
3?
4!
2!
4?
4!
4
5?
4!
2!

You can see that for each otherNums being tested it is running through nums (which is GetNums ) each time. When testing 4 it only takes the first number of nums , but otherwise it is iterating it fully 5 times.

If you're wondering why .Where and the foreach both don't iterate thru the otherNums it is because .Where is run with a deferred execution model - it's only when you do a foreach or something like .ToList() that it executes.

Resharper probably suggested changing the type of the parameter to IEnumerable , because there is no caller who would pass other type than (derived from) IEnumerable , Resharper suggested the simplest type.

ICollection adds only a few properties and methods to IEnumerable from which it derives, most importantly the Count property.

According to this table , the GetEnumerator() method has the same complexity for most classes implementing ICollection .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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