0

I'm looking for something like the ForEach method but it only runs on one element.

// Do something with every element.
SomeList.ForEach(o => DoSomethingWith(o))

// Do something with just the first element, if any, or nothing at all for an empty list.
SomeLine.ForFirst(o => DoSomethingWith(o))

I'm trying to stick with a functional paradigm, and using the First, FirstOrOptional, FirstOrDefault, seem to end up involving a lot of Null checking or exception handling.

What is the Linq one-line way of doing this?

  • 4
    I dont know if you are approaching it correctly. If I needed to do something on the first element in a list then I would run my query and then if not null do whatever I need to do. Easier to read this way in my opinion and easier to debug. Certainly easier to unit test. – Dermo909 Nov 30 '22 at 17:00
  • 4
    You can certainly *create* an extension method for this, encapsulating your null checking there. – David Nov 30 '22 at 17:01
  • Are you sure your query is going to result in at least one result? If so, SingleOrDefault() makes much more sense than FirstOrDefault(). – Amogh Sarpotdar Nov 30 '22 at 17:03
  • 2
    `.ForEach` is not a LINQ method to begin with, as LINQ is for functional-style transformations and this modifies state (or at least, returns nothing). `.ForEach` is specific to `List`, and offers so little over a regular `foreach` statement that I prefer not using it at all and saving the delegate. In this case a `foreach` on a `Take(1)` would do fine. – Jeroen Mostert Nov 30 '22 at 17:04
  • what do you have against good old `var element = myCollection.FirstOrDefault(); if(element != null) DoSomething(element)`? – MakePeaceGreatAgain Nov 30 '22 at 17:11
  • @MakePeaceGreatAgain Moreover, `FirstOrDefault` has a nice overload that defines the default value, so you don't even have to check for null, just give him a dummy instance. – Roman Ryzhiy Nov 30 '22 at 17:13
  • 1
    "I'm trying to stick with a functional paradigm" - but ForEach is not "functional" in this sense, so since you are already using it - just do `FirstOrDefault` and null check the normal way. Anyone reading your code 1 month later (including yourself) will thank you. – Evk Nov 30 '22 at 17:14
  • `var element = collection.FirstOrDefault(new WhateverItIs()); DoSomethingWith(element);` – Roman Ryzhiy Nov 30 '22 at 17:21

2 Answers2

6

Here's an approach which avoids assumptions about whether or not null elements are valid, and also avoids creating a list:

public static void ForFirst<T>(this IEnumerable<T> source, Action<T> action)
{
    using (var iterator = source.GetEnumerator())
    {
        if (iterator.MoveNext())
        {
            action(iterator.Current);
        }
    }
}

Or even, slightly weirdly:

public static void ForFirst<T>(this IEnumerable<T> source, Action<T> action)
{
    // The foreach loop will automatically dispose the iterator
    foreach (var item in source)
    {
        action(item);
        // Stop directly after the first element anyway
        break;
    }
}

(I'd probably not call it ForFirst myself, but that's a different matter.)

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Quite unlikely that OP indeed wants to handle null element in the list, but indeed question is written like he does. – Evk Nov 30 '22 at 17:43
  • 1
    @Evk: I see no reason to make any assumptions one way or another. Sometimes I have collections where elements can be null, and other times I have collections where I assume nothing is null. An empty collection isn't the same as a collection which starts with a null element, and I don't think it's really that unusual to want to differentiate between them. – Jon Skeet Nov 30 '22 at 17:45
  • Making no assumptions is absolutely the way to go. – Mark Fairchild Jan 02 '23 at 09:47
1
collection.Take(1).ToList().ForEach(o => DoSomethingWith(o));

It performs all null and empty checks for you.

Roman Ryzhiy
  • 1,540
  • 8
  • 5