tags:

views:

64

answers:

6
IEnumerable<MyClass> objects = ...
foreach(MyClass obj in objects)
{
  if(obj.someProperty != null)
    SomeFunction(obj.someProperty);
}

I get the feeling I can write a smug LINQ version using a lamda but all my C# experience is 'classical' i.e more Java-like and all this Linq stuff confuses me.

What would it look like, and is it worth doing, or is this kind of Linq usage just seen as showing off "look I know Linq!"

+1  A: 
objects.where(i => i.someProperty != null)
    .ToList()
    .ForEach(i=> SomeFunction(i.someProperty))
cRichter
That's longer than the non-Linq version!
John
@John: Um, in what sense? It has fewer lines and fewer characters as far as I can see...
Jon Skeet
Hmm, the 1-line version was less lines, but I can put my version on 1 line too. I didn't necessarily mean it literally, but on 1 line it was a bit of a mouthful.
John
+8  A: 

LINQ itself doesn't contain anything for this - I'd would use a normal foreach loop:

foreach (var value in objects.Select(x => x.someProperty)
                             .Where(y => y != null))
{
    SomeFunction(value);
}

Or if you want a query expression version:

var query = from obj in objects
            let value = obj.SomeProperty
            where value != null
            select value;
foreach (var value in query)
{
    SomeFunction(value);
}

(I prefer the first version, personally.)

Note that I've performed the selection before the filtering to avoid calling the property twice unnecessarily. It's not for performance reasons so much as I didn't like the redundancy :)

While you can use ToList() and call ForEach() on that, I prefer to use a straight foreach loop, as per Eric's explanation. Basically SomeFunction must incur a side-effect to be useful, and LINQ is designed with side-effect-free functions in mind.

Jon Skeet
This is spot on. If objetcs where a IQueryable, this would also perform better than all the other solutions.
Martin Ingvar Kofoed Jensen
A: 

You can move the if statement into a Where clause of Linq:

IEnumerable<MyClass> objects = ...
foreach(MyClass obj in objects.Where(obj => obj.someProperty != null)
{
    SomeFunction(obj.someProperty);
}

Going further, you can use List's ForEach method:

IEnumerable<MyClass> objects = ...
objects.Where(obj => obj.someProperty != null).ToList()
    .ForEach(obj => SomeFunction(obj.someProperty));

That's making the code slightly harder to read, though. Usually I stick with the typical foreach statement versus List's ForEach, but it's entirely up to you.

Secret Agent Man
The `ForEach` method is not an extension method used for LINQ, it's been in the `List<T>` class since framework 2.0.
Guffa
Using ToList to call the ForEach method will create a list and add references to all objects in 'objetcts'. So I like foreach without using the ForEach method
Martin Ingvar Kofoed Jensen
I guess it was the `Where` method I was looking for, at least partially.
John
@Guffa, yeah I caught that mistake after reading Jon Skeet's answer and tried to edit it before anyone noticed. You were too quick. ;)@Martin, good point. Another reason to use ForEach sparingly.
Secret Agent Man
+1  A: 

Although it can be done with Linq, sometimes its not always necessary. Sometimes you lose readability of your code. For your particular example, I'd leave it alone.

Matthew Abbott
+1  A: 

LINQ is used to create a result, so if you use it to call SomeFunction for each found item, you would be using a side effect of the code to do the main work. Things like that makes the code harder to maintain.

You can use it to filter out the non-null values, though:

foreach(MyClass obj in objects.Where(o => o.someProperty != null)) {
  SomeFunction(obj.someProperty);
}
Guffa
+1  A: 

One option is to use the pattern outlined in the book Linq In Action which uses an extension method to add a ForEach operator to IEnumerable<>

From the book:

public static void ForEach<T> (this IEnumerable<T> source, Action<T> func)
{
   foreach (var item in source)
      func(item)
}

Then you can use that like this:

(from foo in fooList 
  where foo.Name.Contains("bar")
  select foo)
  .ForEach(foo => Console.WriteLine(foo.Name));
Richard