LINQ for beginners: pick the right methods!

LINQ is one of the most loved functionalities by C# developers. It allows you to perform calculations and projections over a collection of items, making your code easy to build and, even more, easy to understand.
As of C# 11, there are tens of methods and overloads you can choose from. Some of them seem similar, but there are some differences that might not be obvious to C# beginners.
In this article, we’re gonna learn the differences between couples of methods, so that you can choose the best one that fits your needs.
First vs FirstOrDefault
Both First
and FirstOrDefault
allow you to get the first item of a collection that matches some requisites passed as a parameter, usually with a Lambda expression:
1 2 |
<span class="token class-name"><span class="token keyword">int</span><span class="token punctuation">[</span><span class="token punctuation">]</span></span> numbers <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name"><span class="token keyword">int</span><span class="token punctuation">[</span><span class="token punctuation">]</span></span> <span class="token punctuation">{</span> <span class="token operator">-</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">12</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token class-name"><span class="token keyword">var</span></span> mod3OrDefault <span class="token operator">=</span> numbers<span class="token punctuation">.</span><span class="token function">FirstOrDefault</span><span class="token punctuation">(</span>n <span class="token operator">=></span> n <span class="token operator">%</span> <span class="token number">3</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name"><span class="token keyword">var</span></span> mod3 <span class="token operator">=</span> numbers<span class="token punctuation">.</span><span class="token function">First</span><span class="token punctuation">(</span>n <span class="token operator">=></span> n <span class="token operator">%</span> <span class="token number">3</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span> |
Using FirstOrDefault
you get the first item that matches the condition. If no items are found you’ll get the default value for that type. The default value depends on the data type:
Data type | Default value |
---|---|
int | 0 |
string | null |
bool | false |
object | null |
To know the default value for a specific type, just run default(string)
.
So, coming back to FirstOrDefault
, we have these two possible outcomes:
1 2 |
<span class="token class-name"><span class="token keyword">int</span><span class="token punctuation">[</span><span class="token punctuation">]</span></span> numbers <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name"><span class="token keyword">int</span><span class="token punctuation">[</span><span class="token punctuation">]</span></span> <span class="token punctuation">{</span> <span class="token operator">-</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">12</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> numbers<span class="token punctuation">.</span><span class="token function">FirstOrDefault</span><span class="token punctuation">(</span>n <span class="token operator">=></span> n <span class="token operator">%</span> <span class="token number">3</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span> numbers<span class="token punctuation">.</span><span class="token function">FirstOrDefault</span><span class="token punctuation">(</span>n <span class="token operator">=></span> n <span class="token operator">%</span> <span class="token number">7</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span> |
On the other hand, First
throws an InvalidOperationException
with the message “Sequence contains no matching element” if no items in the collection match the filter criterion:
1 2 |
<span class="token class-name"><span class="token keyword">int</span><span class="token punctuation">[</span><span class="token punctuation">]</span></span> numbers <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name"><span class="token keyword">int</span><span class="token punctuation">[</span><span class="token punctuation">]</span></span> <span class="token punctuation">{</span> <span class="token operator">-</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">12</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> numbers<span class="token punctuation">.</span><span class="token function">First</span><span class="token punctuation">(</span>n <span class="token operator">=></span> n <span class="token operator">%</span> <span class="token number">3</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span> numbers<span class="token punctuation">.</span><span class="token function">First</span><span class="token punctuation">(</span>n <span class="token operator">=></span> n <span class="token operator">%</span> <span class="token number">7</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span> |
First vs Single
While First
returns the first item that satisfies the condition, even if there are more than two or more, Single
ensures that no more than one item matches that condition.
If there are two or more items that passing the filter, an InvalidOperationException
is thrown with the message “Sequence contains more than one matching element”.
1 2 |
<span class="token class-name"><span class="token keyword">int</span><span class="token punctuation">[</span><span class="token punctuation">]</span></span> numbers <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name"><span class="token keyword">int</span><span class="token punctuation">[</span><span class="token punctuation">]</span></span> <span class="token punctuation">{</span> <span class="token operator">-</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">12</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> numbers<span class="token punctuation">.</span><span class="token function">First</span><span class="token punctuation">(</span>n <span class="token operator">=></span> n <span class="token operator">%</span> <span class="token number">3</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span> numbers<span class="token punctuation">.</span><span class="token function">Single</span><span class="token punctuation">(</span>n <span class="token operator">=></span> n <span class="token operator">%</span> <span class="token number">3</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span> |
Both methods have their corresponding -OrDefault
counterpart: SingleOrDefault
returns the default value if no items are valid.
1 |
<span class="token class-name"><span class="token keyword">int</span><span class="token punctuation">[</span><span class="token punctuation">]</span></span> numbers <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name"><span class="token keyword">int</span><span class="token punctuation">[</span><span class="token punctuation">]</span></span> <span class="token punctuation">{</span> <span class="token operator">-</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">12</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> numbers<span class="token punctuation">.</span><span class="token function">SingleOrDefault</span><span class="token punctuation">(</span>n <span class="token operator">=></span> n <span class="token operator">%</span> <span class="token number">4</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span> numbers<span class="token punctuation">.</span><span class="token function">SingleOrDefault</span><span class="token punctuation">(</span>n <span class="token operator">=></span> n <span class="token operator">%</span> <span class="token number">7</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span> numbers<span class="token punctuation">.</span><span class="token function">SingleOrDefault</span><span class="token punctuation">(</span>n <span class="token operator">=></span> n <span class="token operator">%</span> <span class="token number">3</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span> |
Any vs Count
Both Any
and Count
give you indications about the presence or absence of items for which the specified predicate returns True.
1 |
<span class="token class-name"><span class="token keyword">int</span><span class="token punctuation">[</span><span class="token punctuation">]</span></span> numbers <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name"><span class="token keyword">int</span><span class="token punctuation">[</span><span class="token punctuation">]</span></span> <span class="token punctuation">{</span> <span class="token operator">-</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">12</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> numbers<span class="token punctuation">.</span><span class="token function">Any</span><span class="token punctuation">(</span>n <span class="token operator">=></span> n <span class="token operator">%</span> <span class="token number">3</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span> numbers<span class="token punctuation">.</span><span class="token function">Count</span><span class="token punctuation">(</span>n <span class="token operator">=></span> n <span class="token operator">%</span> <span class="token number">3</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span> |
the difference is that Any
returns a boolean, while Count
returns an integer.
Where vs First
As you remember, First
returns only one item.
If you need all the items that meet the specified criteria, you can use Where
:
1 2 |
<span class="token class-name"><span class="token keyword">int</span><span class="token punctuation">[</span><span class="token punctuation">]</span></span> numbers <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name"><span class="token keyword">int</span><span class="token punctuation">[</span><span class="token punctuation">]</span></span> <span class="token punctuation">{</span> <span class="token operator">-</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">12</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> numbers<span class="token punctuation">.</span><span class="token function">Where</span><span class="token punctuation">(</span>n <span class="token operator">=></span> n <span class="token operator">%</span> <span class="token number">3</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span> |
Sort vs Order
Both Sort
and Order
deal with the sorting of collections.
The main difference is that Sort
sorts the items in place, modifying the original collection.
On the contrary, Order
and OrderBy
create a new collection of items with the same items of the original sequence but sorted.
1 2 |
<span class="token class-name">List<span class="token punctuation"><</span><span class="token keyword">int</span><span class="token punctuation">></span></span> originalNumbers <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">List<span class="token punctuation"><</span><span class="token keyword">int</span><span class="token punctuation">></span></span> <span class="token punctuation">{</span> <span class="token operator">-</span><span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">6</span><span class="token punctuation">}</span><span class="token punctuation">;</span> originalNumbers<span class="token punctuation">.</span><span class="token function">Sort</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> |
Also, notice that Sort
is valid only on List<T>
, and not Arrays or generic Enumerables.
OrderBy
and Order
create a brand-new collection of items.
1 2 |
<span class="token class-name">List<span class="token punctuation"><</span><span class="token keyword">int</span><span class="token punctuation">></span></span> originalNumbers <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">List<span class="token punctuation"><</span><span class="token keyword">int</span><span class="token punctuation">></span></span> <span class="token punctuation">{</span> <span class="token operator">-</span><span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">6</span><span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token class-name"><span class="token keyword">var</span></span> sortedNumbers <span class="token operator">=</span> originalNumbers<span class="token punctuation">.</span><span class="token function">OrderBy</span><span class="token punctuation">(</span>n <span class="token operator">=></span> n<span class="token punctuation">)</span><span class="token punctuation">;</span> |
💡 Starting from C# 11 we can simplify OrderBy(n => n)
and use Order()
!
Further readings
C# collections do not natively expose such methods. They are ALL Extension methods.
If you want to learn what are Extension Methods and how you can write your own methods, have a look at this article:
🔗 How you can create extension methods in C# | Code4IT
Then, in the C# TIPS section of my blog, there are several articles that you might find interesting.
One of these is about a LINQ method that you might want to know: SelectMany
.
This article first appeared on Code4IT 🐧
If you want to learn more about Sort
, the best place is the documentation:
🔗 List.Sort Method | Microsoft Docs
Wrapping up
In this article, we learned the differences between couples of LINQ methods.
Each of them has a purpose, and you should use the right one for each case.
❓ A question for you: talking about performance, which is more efficient: First
or Single
? Drop a message below if you know the answer! 📩
I hope you enjoyed this article! Let’s keep in touch on Twitter or on LinkedIn, if you want! 🤜🤛
Happy coding!
🐧
Source: https://www.code4it.dev/blog/linq-differences