
New LINQ Methods in .NET 9: Index, CountBy, and AggregateBy
LINQ (Language Integrated Query) has always been one of the most powerful features in C#, making it easier to query and transform data in a clean, readable way. With the release of .NET 9, Microsoft introduced the new LINQ methods in .NET 9 – Index, CountBy, and AggregateBy, making LINQ more powerful and expressive. .
These new methods give developers more expressive power and reduce boilerplate code that previously required custom implementations. Let’s dive into each method, see how it worked before .NET 9, and then compare with the new simplified syntax.
Why New LINQ Methods Matter
Before .NET 9, developers often had to rely on a mix of existing LINQ methods, manual loops, or extension methods to achieve things like counting grouped values or working with element indices.
The new methods – Index, CountBy, and AggregateBy—address exactly these scenarios:
- Index – Easily access both the element and its index.
- CountBy – Count occurrences of items grouped by a key.
- AggregateBy – Perform aggregations directly on grouped values.
They make everyday coding tasks more concise, readable, and efficient.
1. Index
The Index method allows you to work with both the item and its index directly, without needing the Select((x, i) => …)
pattern. This improves readability when working with ordered data.
Before .NET 9
public record ProductSale(string Product, int Quantity);
List<ProductSale> productSales = new()
{
new ProductSale("Laptop", 5),
new ProductSale("Smartphone", 10),
new ProductSale("Laptop", 2),
new ProductSale("Tablet", 4)
};
var salesWithIndex = productSales
.Select((productSale, index) => new { ProductSale = productSale, Index = index });
foreach (var item in salesWithIndex)
{
Console.WriteLine($"{item.Index}: {item.ProductSale.Product} - {item.ProductSale.Quantity}");
}
// Output
// 0: Laptop - 5
// 1: Smartphone - 10
// 2: Laptop - 2
// 3: Tablet - 4
In .NET 9
public record ProductSale(string Product, int Quantity);
List<ProductSale> productSales = new()
{
new ProductSale("Laptop", 5),
new ProductSale("Smartphone", 10),
new ProductSale("Laptop", 2),
new ProductSale("Tablet", 4)
};
foreach ((var index, var sale) in productSales .Index())
{
Console.WriteLine($"{index}: {sale.Product} - {sale.Quantity}");
}
// Output
// 0: Laptop - 5
// 1: Smartphone - 10
// 2: Laptop - 2
// 3: Tablet - 4
Instead of juggling with Select((item, index) => …)
, the Index()
method directly gives you a pair of values—Item
and Index
. This makes iteration much simpler and more expressive.
2. CountBy
The CountBy method is a shortcut for counting occurrences of elements by a key. Previously, you had to write a GroupBy
and Count
combination. Now, it’s just one call.
Before .NET 9
public record ProductSale(string Product, int Quantity);
List<ProductSale> productSales = new()
{
new ProductSale("Laptop", 5),
new ProductSale("Smartphone", 10),
new ProductSale("Laptop", 2),
new ProductSale("Tablet", 4)
};
var salesCountByProduct = productSales
.GroupBy(x => x.Product)
.Select(x => new { Product = x.Key, Count = x.Count() });
foreach (var item in salesCountByProduct)
{
Console.WriteLine($"There are {item.Count} sales for the {item.Product}");
}
// Output
// There are 2 sales for the Laptop
// There are 1 sales for the Smartphone
// There are 1 sales for the Tablet
In .NET 9
public record ProductSale(string Product, int Quantity);
List<ProductSale> productSales = new()
{
new ProductSale("Laptop", 5),
new ProductSale("Smartphone", 10),
new ProductSale("Laptop", 2),
new ProductSale("Tablet", 4)
};
var salesCountByProduct = productSales.CountBy(x => x.Product);
foreach (var item in salesCountByProduct)
{
Console.WriteLine($"There are {item.Value} sales for the {item.Key}");
}
// Output
// There are 2 sales for the Laptop
// There are 1 sales for the Smartphone
// There are 1 sales for the Tablet
Here, the query groups the sales by product name and counts how many sales entries exist for each product.
3. AggregateBy
The AggregateBy method lets you perform aggregations directly on grouped values. Instead of grouping and then applying multiple LINQ calls, you can now do it in a single step.
Before .NET 9
public record ProductSale(string Product, int Quantity);
List<ProductSale> productSales = new()
{
new ProductSale("Laptop", 5),
new ProductSale("Smartphone", 10),
new ProductSale("Laptop", 2),
new ProductSale("Tablet", 4)
};
var totalSalesByProduct = productSales
.GroupBy(g => g.Product)
.Select(d => new { Product = d.Key, TotalQuantity = d.Sum(x => x.Quantity) });
foreach (var item in totalSalesByProduct)
{
Console.WriteLine($"{item.Product}: {item.TotalQuantity} items sold");
}
// Output
// Laptop: 7 items sold
// Smartphone: 10 items sold
// Tablet: 4 items sold
In .NET 9
public record ProductSale(string Product, int Quantity);
List<ProductSale> productSales = new()
{
new ProductSale("Laptop", 5),
new ProductSale("Smartphone", 10),
new ProductSale("Laptop", 2),
new ProductSale("Tablet", 4)
};
var totalSalesByProduct = productSales
.AggregateBy(
keySelector: x => x.Product, // Group by Product
seed: 0, // Initial value
(total, sale) => total + sale.Quantity // Aggregation logic
);
foreach (var item in totalSalesByProduct)
{
Console.WriteLine($"{item.Key}: {item.Value} items sold");
}
// Output
// Laptop: 7 items sold
// Smartphone: 10 items sold
// Tablet: 4 items sold
This example groups sales by product and then sums the Quantity
field to get total units sold per product. With just one method call, you avoid the overhead of combining GroupBy
, Select
, and Sum
.
Summary
With .NET 9, LINQ gained three powerful new methods: Index, CountBy, and AggregateBy. These methods simplify common patterns that previously required either verbose LINQ queries or manual loops. By introducing them, Microsoft has made LINQ more intuitive, expressive, and efficient.
Takeaway
In .NET 9, the new LINQ methods bring a big boost in both clarity and productivity. Index removes the need for the old Select((item, index) => …)
pattern, making indexed iteration much cleaner. CountBy streamlines frequency analysis by eliminating the extra GroupBy
and Count
steps, while AggregateBy makes complex aggregation logic straightforward without chaining multiple LINQ calls.
Together, these additions reduce boilerplate code, improve readability, and make queries easier to maintain. If working with collections in .NET 9 or later, adopting these methods is a simple way to write cleaner, more modern LINQ queries that align better with how developers naturally think about data.