October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsPC HealthRecommendedCrashes, freezes, slowdowns? Check your PC nowSpot repairable issues before they interrupt work.Check PCOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
World desk6 min

LINQ Aggregate Operators Beyond Sum and Count: When to Use Aggregate in C#

Aggregate is LINQ's general-purpose reduction. Here is how its three overloads, seeds and result selectors work, when a built-in is clearer, and where IQueryable providers change the result.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use Sum, Count, Average, Min, and Max when they state the operation you mean. Use Enumerable.Aggregate when the rule for combining elements is your own. You supply a starting value (the seed), a function that folds each element into a running value, and optionally a function that converts the final value into a result. That makes Aggregate more general than the named operators, but also harder to read at a glance: a built-in tells the reader the operation, while Aggregate makes the reader work through your lambda.

What the built-in aggregation operators already cover

Microsoft’s aggregation overview lists the standard operators that compute one value from a collection. Each has a direct meaning, which is why they should be the default.

As an Amazon Associate I earn from qualifying purchases.

Operator Computes
Aggregate A custom reduction defined by the caller
Average The mean of a numeric sequence
Count The number of elements
LongCount The number of elements, returned as a 64-bit integer
Max / MaxBy The largest value, or the element with the largest key
Min / MinBy The smallest value, or the element with the smallest key
Sum The total of a numeric sequence

Source: Microsoft Learn, Aggregation operations (C#), dated 2021-09-15. Aggregate is the only custom operation in this group, and it has no C# query-expression syntax, so you call it with method syntax, as in the examples below.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The three Aggregate overloads

The Enumerable.Aggregate reference is the most authoritative description of the overloads. The page linked here is the .NET 5 view of the reference; the overloads below are the ones it documents. Newer .NET versions add operators such as MaxBy and MinBy, so check the version you target.

Overload Parameters Starting value Result when the sequence is empty
Aggregate(func) Source and accumulator The first element of the source Throws InvalidOperationException
Aggregate(seed, func) Source, seed, and accumulator The seed Returns the seed
Aggregate(seed, func, resultSelector) Source, seed, accumulator, and result selector The seed Returns the seed passed through the result selector

Source: Microsoft Learn, Enumerable.Aggregate Method. The seeded overloads are the ones to prefer in most code, because the accumulator type can differ from the element type and the empty case is defined.

How the seeded accumulator runs

With a seed, Aggregate follows three steps:

  1. It sets the running value to the seed. Microsoft’s reference states: “The value of the seed parameter is used as the initial aggregate value.”
  2. For each element in order, it calls the accumulator with the running value and the element. The return value becomes the new running value.
  3. After the last element, it returns the running value. If a result selector was supplied, it returns that function’s output for the final running value.

Microsoft’s example counts the even values in an array. The seed is 0, the running value is an int, and the accumulator adds one only for even elements:

int[] ints = { 4, 8, 8, 3, 9, 0, 7, 8, 2 };
int numEven = ints.Aggregate(0, (total, next) =>
    next % 2 == 0 ? total + 1 : total);
// numEven is 6

Here Count with a predicate would also work, which is the point: this is a counting task, so the built-in is clearer. The value of the example is in showing that the same shape handles rules that have no built-in.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

A custom reduction: summing only the even values

Suppose you want the sum of the even values in a list. No built-in expresses that directly, so you fold the rule into the accumulator. The seed is 0, so an empty list returns 0 and every element is passed through the accumulator:

int[] numbers = { 3, 4, 7, 10 };
int evenSum = numbers.Aggregate(0, (total, next) =>
    next % 2 == 0 ? total + next : total);
// evenSum is 14 (4 + 10)

Why the unseeded overload gives the wrong answer here

The overload without a seed uses the first element as the starting running value, and that element is not passed through the accumulator. In the list above, the first element is 3, which is odd, but it is still added to the total:

int wrong = numbers.Aggregate((total, next) =>
    next % 2 == 0 ? total + next : total);
// wrong is 17 (3 + 4 + 10), not 14

Microsoft specifically warns that the unseeded overload can produce the wrong result when a condition applies to the elements, such as summing only the even values. Use a seeded overload for conditional logic. The unseeded overload also throws InvalidOperationException on an empty sequence, which is a useful signal when empty input is an error and a silent default would hide a bug.

Shaping the final value with a result selector

The third overload converts the accumulator’s final value into a different type. This example keeps an int running count and returns a formatted string:

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
int[] ints = { 4, 8, 8, 3, 9, 0, 7, 8, 2 };
string label = ints.Aggregate(0,
    (total, next) => next % 2 == 0 ? total + 1 : total,
    total => $"{total} even values");
// label is "6 even values"

The result selector runs once, after the loop, so it is the right place for formatting or conversion rather than doing that work in every step.

When a built-in is the better choice

Pick between a named operator and Aggregate by checking these points in order:

  • Is the task a familiar calculation? A total, mean, count, minimum, or maximum should use the named operator. Readers recognise it immediately.
  • Does the rule depend on a condition or a non-numeric result? A filtered tally that returns a string, or a custom accumulator type, is a good fit for Aggregate.
  • Is an empty input possible? Use a seeded overload when an empty sequence should return a defined value. Use the unseeded overload only when an empty sequence should throw.
  • Where does the query run? In LINQ to Objects, Aggregate runs your delegate in process. Against a database provider, the same expression must be translated, and the next section covers the limits.

String building is a common use for the custom form. Microsoft’s LINQ to DataSet method-syntax examples include an Aggregate example that builds a comma-separated list of contact last names; see Microsoft Learn, Method-Based Query Syntax Examples: Aggregate Operators (LINQ to DataSet).

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

LINQ to Objects versus provider-backed IQueryable

The behaviour of Aggregate depends on whether the source is an IEnumerable<T> or an IQueryable<T>. The examples above are IEnumerable<T> calls, which run in your process and accept any C# in the delegate.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

IEnumerable<T> in memory

With Enumerable.Aggregate, the elements are enumerated and your accumulator runs for each one. You control the behaviour completely, so the seed, the accumulator, and the result selector determine the result. The only external dependency is the data already in memory.

IQueryable<T> through a provider

With a provider such as LINQ to Entities, the query is translated into the data source’s language before it runs, so the provider decides what is possible and what the result means. The official LINQ to Entities page on standard query operators, dated 2021-09-15 and updated on the same date, identifies three caveats:

  • Translation support. Not every standard query operator or overload is supported by every LINQ provider. The page points to its list of supported and unsupported methods, so do not assume an Enumerable example translates unchanged to IQueryable<T>. A custom accumulator is the most likely thing to fail translation.
  • Null semantics. How aggregates treat nulls follows the data source and can differ between backends. The page’s example says SQL Server Sum ignores nulls. Do not generalise that to other providers or databases.
  • Conversion and precision. Server-side conversions and precision loss can make Sum or Average return a different value from what you expect in CLR code.

Source: Microsoft Learn, Standard Query Operators in LINQ to Entities Queries. That page describes the .NET Framework LINQ to Entities provider. Newer provider stacks, including EF Core, have their own translation rules, so verify the behaviour against the provider and version you actually run. The practical check is to inspect the SQL the provider generates and compare its results against a small data set with known values, including nulls.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
PC Slower Than It Used to Be?Free scan - under a minute
Outdated Drivers Are Slowing You DownFree scan - exact matches

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.