jonathanpeppers
jonathanpeppers

Reputation: 26505

C# and LINQ - arbitrary statement instead of let

Let's say I'm doing a LINQ query like this (this is LINQ to Objects, BTW):

var rows = 
    from t in totals
    let name = Utilities.GetName(t)
    orderby name
    select t;

So the GetName method just calculates a display name from a Total object and is a decent use of the let keyword. But let's say I have another method, Utilities.Sum() that applies some math on a Total object and sets some properties on it. I can use let to achieve this, like so:

var rows =
    from t in totals
    let unused = Utilities.Sum(t)
    select t;

The thing that is weird here, is that Utilities.Sum() has to return a value, even if I don't use it. Is there a way to use it inside a LINQ statement if it returns void? I obviously can't do something like this:

var rows =
    from t in totals
    Utilities.Sum(t)
    select t;

PS - I know this is probably not good practice to call a method with side effects in a LINQ expression. Just trying to understand LINQ syntax completely.

Upvotes: 1

Views: 800

Answers (4)

Maciej Los
Maciej Los

Reputation: 8591

Please, read my comment to the question. The simplest way to achieve such of functionality is to use query like this:

var rows = from t in totals
    group t by t.name into grp
    select new 
    {
        Name = t.Key,
        Sum = grp.Sum()
    };

Above query returns IEnumerable object.

For further information, please see: 101 LINQ Samples

Upvotes: -1

dav_i
dav_i

Reputation: 28147

Answering the question

No, but you could cheat by creating a Func which just calls the intended method and spits out a random return value, bool for example:

Func<Total, bool> dummy = (total) => 
    { 
        Utilities.Sum(total);
        return true;
    };

var rows = from t in totals
           let unused = dummy(t)
           select t;

But this is not a good idea - it's not particularly readable.


The let statement behind the scenes

What the above query will translate to is something similar to this:

var rows = totals.Select(t => new { t, unused = dummy(t) })
                 .Select(x => x.t);

So another option if you want to use method-syntax instead of query-syntax, what you could do is:

var rows = totals.Select(t =>
               {
                   Utilities.Sum(t);
                   return t;
               });

A little better, but still abusing LINQ.


... but what you should do

But I really see no reason not to just simply loop around totals separately:

foreach (var t in totals)
    Utilities.Sum(t);

Upvotes: 2

Enigmativity
Enigmativity

Reputation: 117174

You should download the "Interactive Extensions" (NuGet Ix-Main) from Microsoft's Reactive Extensions team. It has a load of useful extensions. It'll let you do this:

var rows =
    from t in totals.Do(x => Utilities.Sum(x))
    select t;

It's there to allow side-effects on a traversed enumerable.

Upvotes: 0

Servy
Servy

Reputation: 203822

No, there is no LINQ method that performs an Action on all of the items in the IEnumerable<T>. It was very specifically left out because the designers actively didn't want it to be in there.

Upvotes: 3

Related Questions