DEV Community

Horia Coman
Horia Coman

Posted on • Originally published at horia141.com on

Bug Report #2 - Lazy Select In C#

This is the second in a series of articles about bugs I encounter while working. The first one was about GETUTCDATE() and how it complicates things in longer queries.

Today’s bug is about LINQ and the lazy IEnumerables it produces. A one-off script on which I spent way too much time worked something like this:

IEnumerable<Item> items = RawItems().Select(i => i.Transform());
foreach (var item in items)
    item.name = $"{item.name} #Modified";
UpdateItems(items);

Granted, not the most elegant code. But I thought it was enough to do it’s job. Turns out there’s a simple yet subtle bug occurring. Turns out that Select is quite lazy, so items is more like a promise that if you’re iterating it you’ll get the result of Transform() applied to each element from RawItems. But every time the iterator is used, that computation gets redone.

So the foreach loop actually modified each resulting element from one invocation of the iterator, but all that data was thrown away. When UpdateItems used items it obtained a new version of the derived data, without any of the modifications.

The solution is simple. Either include the modification as part of the Select and alongside Transform. Or make items non-lazy, by turning it into an List or Array, which is what I ended up doing for simplicity’s sake in my actual setup. So the code was now just:

IEnumerable<Item> items = RawItems().Select(i => i.Transform()).ToList();
foreach (var item in items)
    item.name = $"{item.name} #Modified";
UpdateItems(items);

Since the foreach loop and UpdateItems now referenced a list, instead of the iterator over something, the desired behaviour was achieved.

Top comments (0)