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.
Recommended Free Tools
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.
#1 Best Overall
| 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:
- It sets the running value to the seed. Microsoft’s reference states: “The value of the
seedparameter is used as the initial aggregate value.” - For each element in order, it calls the accumulator with the running value and the element. The return value becomes the new running value.
- 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.
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallRank #2
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.
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:
Rank #4
- 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,
Aggregateruns 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).
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.
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.
Best Value
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
Enumerableexample translates unchanged toIQueryable<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
Sumignores nulls. Do not generalise that to other providers or databases. - Conversion and precision. Server-side conversions and precision loss can make
SumorAveragereturn 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.
Quick Recap
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.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →




