Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to convert foreach operation into LINQ if it does two things?

Tags:

c#

foreach

linq

I have the working foreach as follows.

List<Thing> things = new List<Thing>();
foreach (Original original in originals)
  things.Add(new Thing(orignal));

Then, I got smart and LINQified it into the following, still working code.

IEnumerable<Thing> things = originals.Select(origo => new Thing(origo));

Feeling really proud of decimating the number of lines as well and LINQing myself to more clear code I realized that there's also the requirement to update the process table. It's imperative that the update occurs simultanously as we proceed through the transformation. So, with my tail between my legs and feels much less pride, I went back to the original code and added the notification method.

List<Thing> things = new List<Thing>();
foreach (Original original in originals)
{
  things.Add(new Thing(orignal));
  DoTell();
}

My question is if it's possible to keep the LINQie syntax and still be able to incorporate the teller somehow. I'm not hopeful that the code will look nice nor be more readable that way (although, it'd be awesome if it was). However, now it's a matter of academic curiosity and pure stubborness - I'd like to know if it can be done at all.

like image 895
Konrad Viltersten Avatar asked Jan 07 '23 08:01

Konrad Viltersten


2 Answers

There is a really ugly way to do this. It is purely academic.

IEnumerable<Thing> things = originals.Select(origo => {DoTell(); return new Thing(origo)});

You will update your table and return new Thing in Select. Select won't fail because you are using brackets in it and tell that you are returning only new Thing not result of DoTell()

I suggest you to go with foreach because it will really look cleaner in the end. Using LINQ everywhere is not a solution for cleaner/clearer code.

EDIT:

if you still want to go with LINQ, you can do even uglier version of it (one-liner):

var things = things.Select(x => new { o = new Thing(), b = DoTell()}).Select(x=>x.o);

This approach is pure evil. However it works without return statement :)

like image 170
Kamil Budziewski Avatar answered Jan 28 '23 11:01

Kamil Budziewski


This shall work, using original Select Syntax

IEnumerable<Thing> things = originals.Select(origo => 
                                                    {
                                                       DoTell();
                                                       return new Thing(origo);
                                                     });

In case DoTell() needs to be a post call and it needs to use the new Thing created for some internal usage, which is not apparent in this code, then do the following:

IEnumerable<Thing> things = originals.Select(origo => 
                                                        {
                                                           var thing = new Thing(origo);
                                                           DoTell();
                                                           return thing;
                                                         });
like image 30
Mrinal Kamboj Avatar answered Jan 28 '23 12:01

Mrinal Kamboj