c# - Why do changes made in foreach to a Linq grouping select get ignored unless I add ToList()? -
i have following method.
public ienumerable<item> changevalueienumerable() { var items = new list<item>(){ new item("item1", 1), new item("item2", 1), new item("item3", 2), new item("item4", 2), new item("item5", 3) }; var groupeditems = items.groupby(i => i.value) .select(x => new item(x.first().name, x.key)); foreach (var item in groupeditems) { item.calculatedvalue = item.name + item.value; } return groupeditems; }
into groupeditems
collection calculatedvalue
s null. if add tolist()
select
sentence after groupby
calculatedvalue
s has values. example:
var groupeditems = items.groupby(i => i.value) .select(x => new item(x.first().name, x.key)).tolist();
so, question is. why this? want know reason this, solution me add tolist()
update: defition of item
class following
public class item { public string name { get; set; } public int value { get; set; } public string calculatedvalue { get; set; } public item(string name, int value) { this.name = name; this.value = value; } }
var groupeditems = items.groupby(i => i.value) .select(x => new item(x.first().name, x.key));
here, groupeditems
doesn't hold items. ienumerable<t>
returned select
represents computation - precise, represents result of mapping items
new set of items applying function x => new item(x.first().name, x.key)
.
each time iterate on groupeditems
, function applied , new set of items created.
var groupeditems = items.groupby(i => i.value) .select(x => { console.writeline("creating new item"); return new item(x.first().name, x.key)); } foreach(var item in groupeditems); foreach(var item in groupeditems);
this code, example, print "creating new item" twice each item in items
.
in code, you're setting calculatedvalue
of ephemeral item. when foreach loop done, items gone.
by calling tolist
, you're turning "computation" actual collection of items.
instead of calling tolist
, alternatively create another computation represents new set of items calculatedvalue
property set. functional way.
func<item, item> withcalculatedvalue = item => { item.calculatedvalue = item.name + item.value; return item; }; return items.groupby(i => i.value) .select(x => new item(x.first().name, x.key)) .select(withcalculatedvalue);
or use object initializers
return items.groupby(i => i.value) .select(x => new item(x.first().name, x.key) { calculatedvalue = x.first().name + x.key });
if want little bit more research on topic of objects hold computations, google term "monad", prepared confused.
Comments
Post a Comment