2009-04-15 15 views
6

Ayer me escribió el siguiente código C# (se ha reducido un poco de legibilidad):¿Por qué no puedo cambiar elementos de un linq IEnumerable en un bucle for?

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

Así que cada elemento tiene un horaInicio y algunos tienen un EndTime (otros tienen nulo como EndTime).

Si tanto de inicio y fin de los tiempos se conocen quería calcular el tiempo transcurrido:

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

Pero esto no funciona! la colección timeObjects nunca cambia.

Si digo:

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) 

que hace el trabajo.

Me gustaría saber por qué es esto?

Respuesta

11

Su timeObjects es un enumerable de ejecución diferida. Si enumera dos veces sobre la lista, los resultados se evaluarán dos veces, creando nuevos objetos.

Cuando realizó ToList(), creó una copia local de los RESULTADOS de esa consulta/enumerable, que es la razón por la que vio los cambios. Este tipo de consulta LINQ no crea ningún tipo de lista debajo de las cubiertas. La consulta en sí no se realiza hasta que enumere sobre ella. Todo lo que está haciendo en el estado (desde ... seleccionar) es crear la definición de la consulta.

1

La definición original de timeObjects define una expresión LINQ que se evalúa de forma diferida, por lo que cada vez que intente examinar el elemento enumerable de timeObjects, se crearán nuevas instancias de MyObject.

-1

Parece que al llamar a ToList() no es IEnumerable sino IQueryable, por lo que se realizan cambios en los objetos temporales.

Cuestiones relacionadas