1

If I use any integer variable in a LINQ where clause, and after query execution if I modify / initialize the integer variable, then the result set of the LINQ query changes. For example:

static void Main(string[] args)
{    
     int startPos = 0;          
     List<string> intList = new List<string>();
     for (int i = 0; i < 10; i++)
     {
        intList.Add(i.ToString());
     }

     var qResult = from c in intList
                   where Convert.ToInt32(c) >= startPos
                   select c;

     // prints count as 10
     Console.WriteLine("List count is :"+qResult.Count());

     startPos = 5;

     // prints count as 5
     Console.WriteLine("List count is :" + qResult.Count());
}

Output:

List count is :10
List count is :5

In above example you can see that after startPos = 5;, the qResult has changed. I don't understand how this has happened; as far as I know, int is value type.

Is the Linq query again executed at line startPos = 5;? If yes, then will it be a performance impact? And most importantly, am I missing anything here?

stakx - no longer contributing
  • 83,039
  • 20
  • 168
  • 268
Access Denied
  • 886
  • 1
  • 13
  • 24
  • 6
    Deffered execution :) just use `.ToList()` to prevent it. Query is executed while geting data, not when writing `Where` clause. – Kamil Budziewski Jul 31 '13 at 10:16
  • possible duplicate of [What are the benefits of a Deferred Execution in LINQ?](http://stackoverflow.com/questions/7324033/what-are-the-benefits-of-a-deferred-execution-in-linq), [How does the following LINQ statement work?](http://stackoverflow.com/questions/17699877/how-does-the-following-linq-statement-work?newsletter=1&nlcode=180091%7cb8fe) and many others. – CodeCaster Jul 31 '13 at 10:18
  • You should read up on closures: [link](http://en.wikipedia.org/wiki/Closure_(computer_science)). They're pretty neat once you understand them. – Magnus Grindal Bakken Jul 31 '13 at 10:19
  • Just like wudzik stated this is deffered exeuction. In other words, this is normal behavior. When you make a query it is *not* executed. Only when you actually need data is will be executed. – Ron Deijkers Jul 31 '13 at 10:19

5 Answers5

2

qResult is enumerated every time you call .Count(), so when you change startPos in between calls to .Count(), you are really changing the code being executed.

To avoid this, enumerate your list once by calling .ToList(), .ToArray(), or similar:

List<string> qResult = (from c in intList
                   where Convert.ToInt32(c) >=startPos
                   select c).ToList();

This is a very good article on deferred execution in LINQ.

CodingIntrigue
  • 75,930
  • 30
  • 170
  • 176
1

That is because qResult will be an IEnumerable<T> and executed each time you call .Count(). If you want the result to never change simply use ToList() like this:

var qResult = (from c in intList
               where Convert.ToInt32(c) >=startPos
               select c).ToList();
Belogix
  • 8,129
  • 1
  • 27
  • 32
0

.Count() does an enumeration when invoked. it is not like a variable value, so the result is consistent with the expected behaviour.

Tiju John
  • 933
  • 11
  • 28
0

The linq query is executed at the time of call since it use lazy loading, in your case your query is executed in qResult.Count(), if you wish to force the execution call ToList(), or similar function

Swift
  • 1,861
  • 14
  • 17
0

Yes, that's because the qResult is Enumerated each time you call Count() and you are accessing a modified closure into the linq query. You should use a third variable to avoid this behavior:

        int pos = startPos;
        var qResult = from c in intList
                      where Convert.ToInt32(c) >= pos
                      select c;

or enumerate in place:

        var qResult = (from c in intList
                      where Convert.ToInt32(c) >= startPos
                      select c).ToArray();

It is called deffered execution

Tobia Zambon
  • 7,479
  • 3
  • 37
  • 69