How to use lambda expressions with extension methods
Several of the extension methods that are used to implement LINQ define one or more parameters that accept lambda expressions. Like the invoiceOver20000 variable you saw in the last example, these parameters represent delegates that specify the signature of a method. For example, the second parameter of the Where method is defined as a delegate that accepts a function with two parameters. The first parameter is the source element, and the second parameter is a Boolean expression.
The second example in this figure should help you understand how this works. Here, the query uses extension methods and lambda expressions instead of C# clauses. As you review this query, remember that when you use an extension method, you execute it on an instance of the data type it extends. In this case, the extension methods are executed on the invoiceList object, which is an Enumerable type.
The query shown here uses three extension methods, and each method accepts a lambda expression that identifies two parameters. In each case, the first parameter is the source element, which is an invoice in this example. Then, the second parameter of the lambda expression for the Where method is a Boolean expression, the second parameter for the OrderBy method is an expression that specifies the key that's used for sorting, and the second parameter for the Select method is an object that identifies the values to be returned by the query.
The basic syntax of a lambda expression[(]parameterList[)] => expression
A lambda expression that tests a condition
A statement that declares the delegate type
delegate bool compareDel(decimal total);
A statement that defines the lambda expression and assigns it to a variable created from the delegate typecompareDel invoiceOver20000 = total => total > 20000;
Code that executes the lambda expressiondecimal invoiceTotal = 22438.19M;string invoiceMessage = "";invoiceMessage += "Invoice Total: " + invoiceTotal.ToString("c") +"\n" + "Invoice over $20,000: " +invoiceOver20000(invoiceTotal);MessageBox.Show(invoiceMessage, "Invoice Test");
The resulting dialog box
A query that uses extension methods and lambda expressions
var invoices = invoiceList
.Where(i => i.InvoiceTotal > 20000)
.OrderBy(i => i.VendorID)
.Select(i => new { i.VendorID, i.InvoiceTotal });
The same query using C# clauses
var invoices = from invoice in invoiceList
where invoice.InvoiceTotal > 20000
orderby invoice.VendorID
select new { invoice.VendorID, invoice.InvoiceTotal };
Description
Figure 11-12 How to use lambda expressions
The last example is a query that performs the same function as the previous query but uses C# clauses instead of extension methods. If you compare these two queries, I think you'll agree that the one that uses C# clauses is easier to understand. Because of that, we recommend you use this technique whenever possible.
How to use extension methods that implement aggregate functions
In addition to the extension methods you've seen in the last two topics, LINQ provides methods that aren't associated with C# clauses. In this topic, you'll learn about the extension methods that implement aggregate functions. You'll learn about some additional extension methods later in this book.
The table at the top of figure 11-13 lists the extension methods LINQ provides for performing aggregate functions. These methods perform an operation on a set of elements. If you review the descriptions of these methods, you shouldn't have any trouble understanding how they work.
The first example in this figure shows how you can use an aggregate method to summarize the results of a query. Here, the Average method is called on a query that returns the invoice totals for a list of invoices. Notice that when you call a method like this on query results, the query expression must be enclosed in parentheses. Also notice that because the query must be executed before the average can be calculated, the query is executed immediately. Then, the result returned by the Average method is assigned to a decimal variable.
You can also use the aggregate methods to summarize the groups defined by a query. This is illustrated in the second example in this figure. Here, the invoices in a list of Invoice objects are grouped by vendor ID. Then, the where clause uses the Sum method to calculate an invoice total for each vendor so that only those vendors with invoice totals over $10,000 are returned by the query. Notice that a lambda expression is used within the Sum method to indicate which field is to be totaled. In contrast, it wasn't necessary to use a lambda expression in the first example because the query returns a single field.
The Sum method is also used in the orderby clause to sort the grouped invoice totals in descending sequence, and it's used in the select clause to include the invoice total for each vendor in the query results along with the vendor ID. Then, the code that executes the query uses a foreach statement to loop through the results and display the vendor ID and invoice total for each vendor.
Extension methods that implement aggregate functions
A query expression that gets the average of invoice totalsdecimal invoiceAvg = (from invoice in invoiceListselect invoice.InvoiceTotal).Average();
A LINQ query that uses an aggregate with groups
A query expression that gets invoice totals by vendor
var largeVendors =
from invoice in invoiceList
group invoice by invoice.VendorID
into invoiceGroup
where invoiceGroup.Sum(i => i.InvoiceTotal) > 10000
orderby invoiceGroup.Sum(i => i.InvoiceTotal) descending
select new
{
ID = invoiceGroup.Key,
Total = invoiceGroup.Sum(i => i.InvoiceTotal)
};
Code that displays the query resultsstring totalDisplay = "Vendor ID\tInvoice Total\n";foreach (var vendor in largeVendors){ totalDisplay += vendor.ID + "\t\t" + vendor.Total.ToString("c") + "\n";}MessageBox.Show(totalDisplay, "Invoice Totals by Vendor");
Figure 11-13 How to use extension methods that implement aggregate functions