0

I have a class that contains four EnumerableRowCollections, which all point to the same DataTable. The main one will need different combinations of the other three filtered out in different class instances. Since three of them are related, I put them in an array.

EnumerableRowCollection<DataRow> valid;
EnumerableRowCollection<DataRow>[] pending;

All of these collections are defined in the class constructor, but evaluated later due to LINQ's lazy evaluation.

I also have an array of Booleans, which are used to determine which "pending" collections are filtered out of the "valid" collection. These are also assigned in the constructor, and are never changed.

Boolean[] pendingIsValid;

The "valid" collection is filtered like this:

for (var i = 0; i < pending.Length; i++)
    if (pendingIsValid[i] && pending[i].Count() > 0)
        valid = valid.Where(r => !pending[i].Contains(r));

This also occurs in the constructor, but the Where clause is evaluated lazily, as expected.

This works most of the time, however, in a few cases I got a weird exception when the collection evaluation took place down the road.

I get an IndexOutOfRange because of the local iterator variable, i, in my for loop above is set to 3.


Questions:

  1. Can I make "Where" evaluate the array indexer (or other sub-expressions) non-lazily?
  2. How does the iterator get incremented to 3 at all? Does this lazy evaluation count as "re-entering" the loop?
  3. !?!?
Yu Zhang
  • 2,037
  • 6
  • 28
  • 42
JamesFaix
  • 8,050
  • 9
  • 37
  • 73
  • should be resolved from c# 5.0 on, quote Lippert and he should know http://blogs.msdn.com/b/ericlippert/archive/tags/closures/ – phil soady Sep 01 '15 at 21:00

2 Answers2

3

Change it to this:

for (var i = 0; i < pending.Length; i++)
    if (pendingIsValid[i] && pending[i].Count() > 0) 
    {
        var j = i;
        valid = valid.Where(r => !pending[j].Contains(r));
    }

For question #1 - you can make it not lazy by adding .ToList() at the end. However, with the above fix, you can keep it lazy.

Have a read of this: Captured variable in a loop in C# for the explanation

Community
  • 1
  • 1
Rob
  • 26,989
  • 16
  • 82
  • 98
0

Excellent, Rob. I also figured out this while I was waiting for a response, but yours looks a bit cleaner.

for (var i = 0; i < pending.Length; i++) {
    var p = pending[i];
    if (pendingIsValid[i] && p.Count() > 0) 
        valid = valid.Where(r => !p.Contains(r));
}
JamesFaix
  • 8,050
  • 9
  • 37
  • 73