System.Linq.Enumerable.Do Method

public static IEnumerable<TSource> Do<TSource>(this IEnumerable<TSource> source, Action<TSource> action)

Invokes an action for each element in the input sequence. This method is primarily used for side effects.

Parameters

Name Type Description
source IEnumerable<TSource> The IEnumerable<TSource> to perform the action on.
action Action<TSource> The Action<TSource> to invoke for each element.

Returns

Type Description
IEnumerable<TSource> An IEnumerable<TSource> whose elements are the same as the input sequence.

Remarks

The Do method is a convenient way to inspect or perform side effects on elements as they are processed by a LINQ query. Unlike many LINQ methods that transform or filter elements, Do does not change the sequence itself. The action specified will be executed exactly once for each element in the sequence. It's important to note that Do is evaluated lazily, meaning the action will only be performed when the resulting sequence is iterated over.

Consider using Do judiciously. Overuse of side effects within LINQ queries can make code harder to understand and debug. For tasks that inherently involve side effects (like logging or updating state), it might be more appropriate to perform those operations outside of the LINQ query pipeline or use explicit loops.

Examples

Example 1: Logging elements

This example demonstrates how to use Do to log each number in a sequence to the console.


using System;
using System.Collections.Generic;
using System.Linq;

public class Example
{
    public static void Main(string[] args)
    {
        IEnumerable<int> numbers = new List<int> { 1, 2, 3, 4, 5 };

        var processedNumbers = numbers.Do(n => Console.WriteLine($"Processing: {n}"));

        Console.WriteLine("Starting iteration...");
        foreach (var num in processedNumbers)
        {
            Console.WriteLine($"Received: {num}");
        }
        Console.WriteLine("Iteration finished.");
    }
}
                    

Output:


Starting iteration...
Processing: 1
Received: 1
Processing: 2
Received: 2
Processing: 3
Received: 3
Processing: 4
Received: 4
Processing: 5
Received: 5
Iteration finished.
                    

Example 2: Using Do with Where and Select

This example shows how Do executes its action in conjunction with other LINQ operations.


using System;
using System.Collections.Generic;
using System.Linq;

public class Example
{
    public static void Main(string[] args)
    {
        var results = Enumerable.Range(1, 10)
            .Do(i => Console.WriteLine($"Generated: {i}"))
            .Where(i => i % 2 == 0)
            .Do(i => Console.WriteLine($"Filtered (even): {i}"))
            .Select(i => i * 2)
            .Do(i => Console.WriteLine($"Mapped (doubled): {i}"))
            .ToList(); // ToList() forces execution
    }
}
                    

Output:


Generated: 1
Generated: 2
Filtered (even): 2
Mapped (doubled): 4
Generated: 3
Generated: 4
Filtered (even): 4
Mapped (doubled): 8
Generated: 5
Generated: 6
Filtered (even): 6
Mapped (doubled): 12
Generated: 7
Generated: 8
Filtered (even): 8
Mapped (doubled): 16
Generated: 9
Generated: 10
Filtered (even): 10
Mapped (doubled): 20