C# Linq ForEach – How to Linq style loop over items in a List

Contents

Introduction

First a quick warning, I have occasionally used this construct in my code, but as part of writing this article I’ve come round to the idea that it’s often a bad idea! That said, to paraphrase Randall Munroe: “The Rules of [coding] are like magic spells. If you never acquire them, then not using them says nothing.” So let’s do this, shall we?

List.ForEach() example

The following code will print out one line for each element in a list using Linq like syntax:

var numbers = new List<int>() { 1, 2, 3 };
numbers.ForEach(x => Console.WriteLine(x));

/* this code outputs:
1
2
3
*/

Note though, that this is a List extension method in the same System.Collections.Generic as List itself. So there is nothing Linq about this method or syntax, it just looks like Linq.

C# Linq ForEach Where – Execute an action foreach item in a collect where a condition is true

The example above will perform the WriteLine method on every item in a list. Sometimes though, you only want to perform such an action on certain items.

This is easy to do by using a where clause to filter the items, before using foreach. But be careful! the where clause will result in an IEnumerable, which needs to be converted to a List before we can use List’s ForEach. For example:

var numbers = new List<int>() { 1, 2, 3, 4, 5 };
numbers.Where(x => x > 2)
    .ToList()
    .ForEach(x => Console.WriteLine(x));

/* this code outputs:
3
4
5
*/

Linq ForEach Where In

This is one for those coming from an SQL background, for them WHERE IN is a very common construct. It can be done in C# using .Contains() as follows:

var numbers = new List<int>() { 1, 2, 3, 4, 5 };
var squares = new List<int>() { 2, 4, 9 };
numbers.Where(x => squares.Contains(x))
    .ToList()
    .ForEach(x => Console.WriteLine(x));

/* this code outputs:
2
4
*/

Linq ForEach Multiple Actions

All the examples so far have used Console.WriteLine() to print the result, but what if we want to do perform multiple actions within a Linq style ForEach? That can be achieved as follows:

var numbers = new List<int>() { 1, 2, 3, 4, 5 };

numbers.Where(num => num > 2)
  .ToList()
  .ForEach( number =>
  {
    var square = number * number;
    Console.WriteLine($"{number} squared is {square}");
  });

/* this code outputs:
3 squared is 9
4 squared is 16
5 squared is 25
*/

But hang on, the .ToList() smells like a hack, it will create a new copy of the data, potentially wasting memory and computation time. Can we do any better?

Well, at this point you might as well use a foreach loop instead:

var numbers = new List<int>() { 1, 2, 3, 4, 5 };

foreach (var number in numbers.Where(num => num > 2))
{
  var square = number * number;
  Console.WriteLine($"{number} squared is {square}");
}

/* this code outputs:
3 squared is 9
4 squared is 16
5 squared is 25
*/

But there is another way… We could implement a Linq style .ForEach ourselves if we really want to:

C# Linq ForEach IEnumerable – implementing it ourselves

It turns out that it’s really rather simple to implement this ourselves:

public static void ForEach<T>(this IEnumerable<T> sequence, Action<T> action)
{
  if (action == null)
  {
    throw new ArgumentNullException(nameof(action));
  }

  foreach(T item in sequence)
  {
    action(item);
  }
}

With our own implementation of .ForEach for IEnumerables we can then write code like this (note, no need for .ToList() and it’s associated performance problems!):

var numbers = new List<int>() { 1, 2, 3, 4, 5 };
numbers.Where(x => x > 2).ForEach(x => Console.WriteLine(x));

/* this code outputs:
3
4
5
*/

But hang on, if it’s that easy, why isn’t it part of the standard implementation?

Why doesn’t .ForEach work with IEnumerables out of the box?

As explained above, the ForEach Linq extension doesn’t work for IEnumerables, it’s only works for on a List. Why is that?

The closest thing I could find to an official answer on this came from this blog post, to summarise: “[it] violates the functional programming principles… [and] adds zero new representational power to the language”.

The first argument is that Linq expressions are assumed to not have side effects, while .ForEach is explicitly there to create side effects. This results in code which potentially doesn’t do what the person reading it expects.

I also found this argument about lazy evaluation interesting: when I’m working with an IEnumerable I don’t expect the expression to be evaluated until I call .ToList() or similar – should calling .ForEach() on an IEnumerable evaluate it? I’m pretty sure that yes, it should, but I can see that it’s not obvious (so probably worth avoiding).

The second official argument is basically, why would you bother when you have foreach? And while my coding style (heavily influenced by stylecop!) means .ForEach can look a lot cleaner, I have to admit that using a foreach loop is easier to remember, clear what it’s doing and isn’t exactly a hardship:

var numbers = new List<int>() { 1, 2, 3, 4, 5 };

foreach (var number in numbers.Where(num => num > 2))
{
  Console.WriteLine(number);
}

/* this code outputs:
3
4
5
*/

Conclusion

.ForEach() is easy to use, but it’s for List only (there is no true Linq ForEach).

.ToList() is a nice hack that we can use with IEnumerables (but probably shouldn’t)

It’s pretty easy to add our own IEnumerable .ForEach(), but it’s probably not worth it.

Just use foreach when you have an IEnumerable and your aim is to cause side effects.

I feel that I’ve acquired the knowledge of how to use a Linq style ForEach in my code, but I feel enlightened enough to know that (unless I already have a List) my code is probably better off without it.

If you’re into Linq, you might like this post on Except and other set based Linq extension methods: C# Linq Except: How to Get Items Not In Another List

One Reply to “C# Linq ForEach – How to Linq style loop over items in a List”

Leave a Reply

Your email address will not be published. Required fields are marked *