I have the following scenario where I want to add some items to a List...
List<T> items = new List<T>();
IEnumerable<T> addItems = someCollection.Where(...);
items.AddRange(addItems);
Using this code, no items are added to the list but if I add a .ToList() after then Linq statement then the items are added correctly. 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.
Can someone please clear up why this happens?
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>
).