Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I change elements from a linq IEnumerable in a for loop?

Tags:

c#

linq

Yesterday I wrote the following c# code (shortened a bit for legibility):

 var timeObjects = ( from obj in someList
                     where ( obj.StartTime != null )
                     select new MyObject()
                     {
                        StartTime= obj.StartTime.Value,
                        EndTime = obj.EndTime
                     } )

So each item has a startTime and some have an EndTime (others have null as EndTime).

If both start and endtime are known I wanted to calculate the elapsed time:

foreach ( var item in timeObjects)
{
    if ( item.EndTime  == null )
    {
      item.elapsed = 0;
    }
    else
    {
      item.elapsed = ( item.EndTime.Value - item.StartTime).Minutes;
    }
}

But this doesn't work! the timeObjects collection never changes.

If I say:

 var timeObjects = ( from obj in someList
                     where ( obj.StartTime != null )
                     select new MyObject()
                     {
                         StartTime= obj.StartTime.Value,
                         EndTime = obj.EndTime
                     } ).ToList();

foreach ( var item in timeObjects)
{
    if ( item.EndTime  == null )
    {
      item.elapsed = 0;
    }
    else
    {
      item.elapsed = ( item.EndTime.Value - item.StartTime).Minutes;
    }
}
//(only change is the ToList() at the end of the linq statement)

it does work.

I'd very much like to know why this is?

like image 818
Jauco Avatar asked Apr 15 '09 13:04

Jauco


1 Answers

Your timeObjects is a delayed-execution enumerable. If you enumerate over the list twice, the results will actually be evaluated twice, creating new objects.

When you performed ToList(), it created a local copy of the RESULTS of that query/enumerable, which is why you saw the changes. This sort of LINQ query doesn't create any sort of list under the covers. The query itself isn't performed until you enumerate over it. All you're doing in the (from ... select) state is creating the query definition.

like image 76
Adam Robinson Avatar answered Sep 30 '22 19:09

Adam Robinson