LINQ is the idiomatic way to work with data in C#, from in-memory lists to databases via EF Core.
LINQ (Language Integrated Query) is a set of extension methods on IEnumerable<T> in System.Linq. You chain them into a pipeline:
Where(pred)filters,Select(f)projects,SelectManyflattens.OrderBy,ThenBy,OrderByDescendingsort.GroupBy(keySelector)produces groups with aKey.First,FirstOrDefault,Single,Any,All,Count,Sum,Average,Min,Max,MaxBy.Distinct,Take,Skip,Chunk,Zip,Join,ToDictionary,ToLookup.- .NET 9 added
CountByandAggregateBy.
Most operators are lazy (deferred execution): Where and Select build a query that runs only when you iterate it or call a materializing method like ToList(), ToArray(), Count() or First(). A query enumerated twice runs twice, so materialize once if you reuse the results or the source is expensive.
There is also query syntax (from p in people where p.Age > 30 select p.Name), which compiles to the same method calls; method syntax is more common.
The same operators on IQueryable<T> (Entity Framework Core) are translated into SQL instead of running in memory, which is why LINQ knowledge carries over to data access.
First throws if nothing matches; FirstOrDefault returns default (null or 0). Single additionally throws if more than one item matches.
Example
var people = new List<Person>
{
new("Ada", "London", 36), new("Alan", "London", 41),
new("Grace", "NYC", 85), new("Linus", "Helsinki", 28),
};
var names = people.Where(p => p.Age > 30)
.OrderBy(p => p.Name)
.Select(p => p.Name);
Console.WriteLine(string.Join(", ", names)); // Ada, Alan, Grace
foreach (var g in people.GroupBy(p => p.City))
Console.WriteLine($"{g.Key}: {g.Count()}"); // London: 2 / NYC: 1 / Helsinki: 1
Console.WriteLine(people.Average(p => p.Age)); // 47.5
Console.WriteLine(people.MaxBy(p => p.Age)!.Name); // Grace
Console.WriteLine(people.Any(p => p.City == "Paris")); // False
var byCity = people.CountBy(p => p.City).ToDictionary();
Console.WriteLine(byCity["London"]); // 2
record Person(string Name, string City, int Age);Remember
- Chain Where, Select, OrderBy, GroupBy into readable pipelines
- Most LINQ operators are lazy until enumerated or materialized
- Call ToList() once when you reuse results
- The same operators translate to SQL on IQueryable
Watch out for
- Enumerating a deferred query several times, re-running expensive work each time.