Just a quick question for people who know the inner workings of .Net better than me ::- ). I am JUST MAKING SURE that I understand something.
The way I see it, when you run a LINQ in a foreach, the LINQ enumerator is evaluated (run), it returns a collection and the foreach proceeds on that collection. But... still, I am unsure:
foreach (VCCTreeItem ti in (from treeItems in TreeItems select treeItems))
Is the LINQ statement re-evaluated (executed) at each loop? I would think (and hope) that NO. However, when doing operations with a collection in a foreach
, you get error messages at run-time if the collection is modified. Which led me to believe that something fishy may be happening behind the scenes. I never had the time to disassemble / check this in detail, so this is why I'm asking you this. I'm sure some of you know the answer from the top of their head ::- D.
Oh, and I think I can ask the same question about:
foreach (VCCTreeItem ti in TreeItems)
If TreeItems is a property in who开发者_如何学编程se get
I do some operations, the property will be evaluated, returned as a value and the foreach will operate on that value.
The IEnumerable
is not reevaluated. A foreach
statement like this:
IEnumerable<Foo> enumerable = ...;
foreach (Foo f in enumerable) {
...
}
corresponds to this (EDIT: enumerator
is also put in a using
block, as shown by @Double Down):
IEnumerable<Foo> enumerable = ...;
IEnumerator<Foo> enumerator = enumerable.GetEnumerator();
while (enumerator.MoveNext()) {
Foo f = enumerator.Current;
...
}
So if you have some costly operation that produces the collection you're looping over, it's not a problem; it will only be produced once. In LINQ, though, as @Double Down says, most results are produced lazily - so the call to GetEnumerator()
does almost nothing, while the result is produced incrementally by each call to MoveNext()
. Overall, this is about as time consuming as producing the entire list in one operation, but it conserves memory (an actual List
containing all elements is never produced; you get one element at a time, then discard it).
Linq is doing late bound evaluation (using the yield keyword). It's evaluated for only the next item when you call MoveNext() in an IEnumerator, it's not recomputed from scratch in each move next call.
As you already know, your foreach loop evaluates to
using (var enumerator = enumerable.GetEnumerator())
{
while (enumerator.MoveNext())
{
// Loop body.
}
}
精彩评论