List.AddRange with IEnumerable<T> parameter not working?

I guess this is due to deferred execution but I would have thought that given the List.AddRange function accepts an IEnumerable that it would enumerate the items to be added.

It does. There is a short circuit for ICollection<T> (which you wouldn't hit in this case), which would cause it to use ICollection<T>.CopyTo instead of enumerating the items, but otherwise, it will enumerate the collection.

For a working example, try:

using System;
using System.Linq;
using System.Collections.Generic;

internal class Program
{
    private static List<T> RunQuery<T>(IEnumerable<T> someCollection, Func<T, bool> predicate)
    {
        List<T> items = new List<T>();
        IEnumerable<T> addItems = someCollection.Where(predicate);
        items.AddRange(addItems);
        return items;
    }

    static void Main()
    {
        var values = Enumerable.Range(0, 1000);

        List<int> results = RunQuery(values, i => i >= 500);

        Console.WriteLine(results.Count);
        Console.WriteLine("Press key to exit:");
        Console.ReadKey();
    }
}

This uses your exact code, and will print out 500 (the proper number of items in the List<T>).


I would have thought that given the List.AddRange function accepts an IEnumerable that it would enumerate the items to be added.

I tried the below and AddRange(IEnumerable<T>) does work

List<string> someCollection = new List<string>{"A", "B", "C"};
List<string> items = new List<string>();
IEnumerable<string> addItems = someCollection.Where(x => x != "");
items.AddRange(addItems);

Thanks for the replies. I tried to simplify the code for this example but as usual, the devil's in the details!

Between the .Where() statement and the AddRange() call the code was (deep down) clearing the source ('items' in this example) list. The developer didn't realise that the filter was deferred until the AddRange() call at which point they had already cleared the source list.

Glad to know I haven't lost the plot :)