Apply function to all elements of collection through LINQ
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
In C#, LINQ is primarily about querying and transforming sequences, not performing side effects. That distinction matters when you want to “apply a function to all elements.” If the goal is to create a transformed sequence, LINQ is a good fit. If the goal is to run an action for side effects, a normal loop is often clearer.
Use Select for Transformation
When each input element should become a new output value, Select is the correct LINQ operator.
This does not mutate the original sequence. It projects each item into a new one.
That is the core LINQ mental model: query and projection first, side effects second.
Remember That LINQ Is Deferred by Default
Many LINQ operators, including Select, use deferred execution. That means the projection does not run until the sequence is enumerated.
This matters because developers sometimes expect the function to run immediately just by writing the LINQ expression.
Use a Loop for Side Effects
If the goal is logging, database writes, mutation, or any action that returns no meaningful value, a foreach loop is usually the right tool.
This is more explicit than abusing LINQ for side effects and is easier to read in code reviews.
List<T>.ForEach Exists, but Use It Deliberately
If the collection is specifically a List<T>, you can call ForEach.
This is convenient, but it is not a LINQ operator and does not work on every IEnumerable<T>. It also encourages inline side-effect lambdas that can become hard to debug when they grow.
So if the collection type is not already a List<T>, converting it just to call ForEach is usually a sign that a plain foreach statement would have been clearer.
Transform Then Materialize
A common pattern is applying several pure transformations and then materializing once at the end.
This is where LINQ is strongest: declarative filtering, mapping, and aggregation.
Avoid Hidden Side Effects in LINQ Chains
LINQ queries that mutate outside state are technically possible, but they are usually a design smell.
This works, but it mixes transformation with mutation and depends on enumeration timing. In most production code, a simple loop is clearer and safer.
Choosing the Right Tool
Use this rule:
- Want new values from old values:
Select. - Want filtering:
Where. - Want one combined value:
Aggregate,Sum,Count, and similar. - Want side effects only:
foreachorList<T>.ForEach.
That separation keeps code intent obvious.
Common Pitfalls
- Using LINQ for side effects and assuming it executes immediately.
- Forgetting to materialize a deferred query when needed.
- Calling
List<T>.ForEachand thinking it is a generalIEnumerable<T>feature. - Mutating captured external state inside
Selectand creating subtle timing bugs. - Replacing a straightforward loop with LINQ even when it makes the code less readable.
Summary
- Use LINQ
Selectwhen you want to transform each element into a new value. - LINQ queries are often deferred, so execution happens on enumeration.
- Use
foreachfor side effects such as logging or mutation. - Keep LINQ chains pure and focused on querying or projection.
- Choose the construct that makes intent clearest, not just the shortest one.

