0

Suppose I have this :

IEnumerable<MyObject> StructsTemp;

I wrote n queries on StructsTemp, so that it populates from the DB, and so on. Later, I execute them calling .ToList() :

IList<MyObject> StructsFinal = StructsTemp.ToList();
... some queries on StructsFinal ....
StructsTemp = StructsFinal;

What about if later I do this?

StructsTemp.Count()

Will it re-execute the n queries on StructsTemp? Will this re-execute StructsTemp.ToList()? Will this re-execute all queries on StructsFinal?

Jodrell
  • 31,518
  • 3
  • 75
  • 114
markzzz
  • 44,504
  • 107
  • 265
  • 458

2 Answers2

1

If you assign a reference of List<T> to the variable StructsTemp, the IEnumerable<T> actuallyis a List<T> and will use it's Count property instead of enumerating the underlying sequence.

var numbers = new []{ 1,2,3 };
IEnumerable<int>evenNumbers = numbers.Where(i=> i % 2 == 0);
// deferred, will enumerate the sequence to count the even numbers
int count = evenNumbers.Count();
evenNumbers = evenNumbers.ToList();
// not deferred, using the Count property of List<T>
count = evenNumbers.Count();

So the latter will always return the same value since it's persisted in a new collection. The former can return a different result on each iteration when the underlying collection has changed(f.e. numbers.Remove(2) causes evenNumbers.Count to be 0) .

Edit:

Here's a more meaningful demo of that behaviour: http://ideone.com/91Yrh

Tim Schmelter
  • 411,418
  • 61
  • 614
  • 859
  • so evenNumbers = evenNumbers.ToList(); will "turn" an IEnumerable to a List? :O I don't think so... – markzzz Jul 20 '12 at 12:11
  • @markzzz: `IList` implements `IEnumerable` so every list is also an ienumerable implicitely. That's just inheritance. But the reference changes from a linq query which has an underlying collection to a different `List`. – Tim Schmelter Jul 20 '12 at 12:17
  • That's not clear at all :) Suppose, before `int count = evenNumbers.Count();` I "cycle" evenNumbers with a foreach : what is that? Not a List :O – markzzz Jul 20 '12 at 12:22
  • Also : if I didnt evenNumbers = evenNumbers.ToList(); , every evenNumbers.Count(); will execute the query (where) every time? – markzzz Jul 20 '12 at 12:50
  • @markzzz: I haven't understand your first comment at all(what's _cycle_?). The answer to your last coment: Yes. And that could be very expensive, understand the `Where` as an `if` in a loop. – Tim Schmelter Jul 20 '12 at 12:54
  • I mean "cycling" the list with a foreach. Foreach will turn the unmaterialized list (???) into what? A Enumerable? (which is not materialized?) :O – markzzz Jul 20 '12 at 12:56
  • What I also find bizzare is this : after evenNumbers = evenNumbers.ToList(); , evenNumbers become a List from "somethings that I didn't understand yet", and I can't use it properly (in fact I can't use evenNumbers.Count property, which it is allowed with List). First time I see this behaviour on OP language... – markzzz Jul 20 '12 at 13:08
  • @markzzz: Here's a sample which demonstrates what i mean. It prints a _"`veryExpensiveMethod`"_ 10 times. 5 for the `Where` and 5 times for the `ToList`: http://ideone.com/91Yrh After the `ToList` you could call `Count()` 1000 times without an additonal call of the _"`veryExpensiveMethod`"_. – Tim Schmelter Jul 20 '12 at 13:08
  • 1
    @markzzz: You **can** use the `evenNumbers.Count` property if you want. You just have to cast it accordingly, that is what `Enumerable.Count()` also tries first before it enumerates the sequence: `((ICollection)evenNumbers).Count`. But that's not necessary as i've already mentioned since `Enumerable.Count` checks it first. – Tim Schmelter Jul 20 '12 at 13:34
  • Thank you! This means with .NET and "statically linked" ? – markzzz Jul 20 '12 at 13:38
  • @markzzz: You're welcome, although i don't understand what you mean by _"statically linked"_. Extension methods are always static but that has nothing to do with this topic (inheritance and [`iterator blocks`](http://csharpindepth.com/articles/chapter6/iteratorblockimplementation.aspx)). – Tim Schmelter Jul 20 '12 at 13:45
  • That's also why, turn it into a list, I need .ToList() at the end if I do `nums=nums.Where(i=> veryExpensiveMethod(i))` (because, otherwise, this query will be never executed). Right? – markzzz Jul 20 '12 at 13:46
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/14183/discussion-between-tim-schmelter-and-markzzz) – Tim Schmelter Jul 20 '12 at 13:51
0

ToList() will force the evaluatation of StructsTemp, whatever that is, but it has no effect on the subsequent Linq.

... some queries on StructsFinal .... may or may not be lazy evaluated, lets assume it\they are.

the Count() extension is not lazy so would force the execution of ... some queries on StructsFinal ....,

As an aside, if the result of ... some queries on StructsFinal .... implements ICollection<T>, like IList<T> does, then the Count() extension will just access the Count property of the result.

Jodrell
  • 31,518
  • 3
  • 75
  • 114