CHAPTER 14 ■ EXTENSION METHODS 508 public static IEnumerable GeneralIterator this IList theList, Func finalState, Func incrementer { while !finalStatetheList { yield return theL
Trang 1CHAPTER 14 ■ EXTENSION METHODS
502
changed C#, on the other hand, offers a hybrid environment in which you are free to implement functional programming if you choose Also, those familiar with the Standard Template Library (STL) will get a familiar feeling from this style of programming STL swept through the C++ programming community back in the early 1990s and encouraged a more functional programming thought process
Operation Chaining
Using extension methods, operation chaining becomes a more natural process Again, it’s nothing that you could not have done in the C# 2.0 days using plain static methods and anonymous methods However, with the streamlined syntax, chaining actually removes the clutter and can trigger some innovative thinking Let’s start with the example from the previous section, in which we took a list of integers and transformed them into a list of doubles This time, we’ll look at how we can actually chain operations in a fluid way Let’s suppose that after dividing the integers by 3, we want to then compute the square of the result The following code shows how to do that:
public static IEnumerable<R> Transform<T, R>(
this IEnumerable<T> input,
Func<T, R> op ) {
foreach( var item in input ) {
yield return op( item );
Trang 2CHAPTER 14 ■ EXENTENSION METHODS
503
new Func<double, double>( Square );
var result = CreateInfiniteList()
Transform( divideByThree )
Transform( squareNumber );
var iter = result.GetEnumerator();
for( int i = 0; i < 25; ++i ) {
Isn’t that cool? In one statement of code, I took an infinite list of integers and applied a divisor
followed by a squaring operation, and the end result is a lazy-evaluated IEnumerable<double> type that computes each element as needed Functional programming is actually pretty useful when you look at it this way Of course, you could chain as many operations as necessary For example, you might want to append a rounding operation at the end Or maybe you want to append a filtering operation so that only the results that match a certain criteria are considered To do that, you could create a generic Filter<T> extension method, similar to Transform<T>, that takes a predicate delegate as a parameter and uses it to filter the items in the collection
At this point, I’m sure that you’re thinking of all the really useful extension methods you could
create to manipulate data You might be wondering if a host of these extension methods already exists Check out the System.Linq.Enumerable class This class provides a whole host of extension methods that are typically used with LINQ, which I cover in Chapter 16 All these extension methods operate on types
of IEnumerable<T> Also, the System.Linq.Queryable class provides the same extension methods for types that implement IQueryable<T>, which derives from IEnumerable<T>
Custom Iterators
Chapter 9 covered iterators, which were added to the language in C# 2.0 I described some ways you
could create custom iterators Extension methods offer even more flexibility to create custom iterators for collections in a very expressive way By default, every collection that implements IEnumerable or
IEnumerable<T> has a forward iterator, so a custom iterator would be necessary to walk through a
collection in a different way than its default iterator Also, you will need to create a custom iterator for
types that don’t support IEnumerable<T>, as I’ll show in the next section, “Borrowing from Functional
Programming.” Let’s look at how you can use extension methods to implement custom iterators on
types implementing IEnumerable<T>
For example, imagine a two-dimensional matrix implemented as a List<List<int>> type When
performing some operations on such matrices, it’s common to require an iterator that walks through the matrix in row-major fashion What that means is that the iterator walks all the items of the first row, then the second row, and so on until it reaches the end of the last row
You could iterate through the matrix in row-major form as shown here:
Trang 3CHAPTER 14 ■ EXTENSION METHODS
// One way of iterating the matrix
foreach( var list in matrix ) {
foreach( var item in list ) {
public static IEnumerable<T> GetRowMajorIterator<T>(
this List<List<T>> matrix ) {
foreach( var row in matrix ) {
foreach( var item in row ) {
yield return item;
static void Main() {
var matrix = new List<List<int>> {
new List<int> { 1, 2, 3 },
new List<int> { 4, 5, 6 },
new List<int> { 7, 8, 9 }
};
// A more elegant way to enumerate the items
foreach( var item in matrix.GetRowMajorIterator() ) {
Trang 4CHAPTER 14 ■ EXENTENSION METHODS
505
In this version, I have externalized the iteration into the GetRowMajorIterator<T> extension method
At the same time, I made the extension method generic so it will accept two-dimensional nested lists
that contain any type, thus making it a bit more reusable
Borrowing from Functional Programming
You might have already noticed that many of the new features added in C# 3.0 facilitate a functional
programming model You’ve always been able to implement functional programming models in C#, but the new language features make it easier syntactically by making the language more expressive
Sometimes, the functional model facilitates easier solutions to various problems Various languages are categorized as functional languages, and Lisp is one of them
If you’ve ever programmed using Lisp, you know that the list is one of the core constructs in that
language In C#, we can model such a list using the following interface definition at the core:
public interface IList<T>
namespaces
The structure of this list is a bit different from the average linked list implementation Notice that
instead of one node containing a value and a pointer to the next node, it instead contains the value at
the node and then a reference to the rest of the list In fact, it’s rather recursive in nature That’s no
surprise because recursive techniques are part of the functional programming model For example, if
you were to represent a list on paper by writing values within parentheses, a traditional list might look
like the following:
Trang 5CHAPTER 14 ■ EXTENSION METHODS
public static IList<T> CreateList( IEnumerable<T> items ) {
IEnumerator<T> iter = items.GetEnumerator();
return CreateList( iter );
public static IEnumerable<T>
LinkListIterator<T>( this IList<T> theList ) {
Trang 6CHAPTER 14 ■ EXENTENSION METHODS
static void Main() {
var listInts = new List<int> { 1, 2, 3, 4 };
First, notice in Main that I am initializing an instance of MyList<int> using a List<int> The
CreateList static method recursively populates MyList<int> using these values Once CreateList is
finished, we have an instance of MyList<int> that can be visualized as follows:
1, 2, 3, 4,
In the example, notice that the LinkListIterator<T> method creates a forward iterator by making
some assumptions about how to determine whether it has reached the end of the list and how to
increment the cursor during iteration That is, it starts at the head and assumed it has finished iterating once the current node’s tail is null What if we externalized this information? For example, what if we
wanted to allow the user to parameterize what it means to iterate, such as iterate forwards, backwards, circularly, and so on? How could we do that? If the idea of delegates pops into your mind, you’re right on track Check out the following revised version of the iterator extension method and the Main method:
public static class CustomIterators
{
Trang 7CHAPTER 14 ■ EXTENSION METHODS
508
public static IEnumerable<T>
GeneralIterator<T>( this IList<T> theList,
Func<IList<T>, bool> finalState,
Func<IList<T>, IList<T>> incrementer ) {
while( !finalState(theList) ) {
yield return theList.Head;
theList = incrementer( theList );
static void Main() {
var listInts = new List<int> { 1, 2, 3, 4 };
var linkList =
MyList<int>.CreateList( listInts );
var iterator = linkList.GeneralIterator( delegate( IList<int> list ) {
return list.Tail == null;
GeneralIterator<T> method can be used to iterate over every other item in the list simply by modifying the delegate passed in through the incrementer parameter
■ Note Some of you might already be familiar with lambda expressions, which were introduced in C# 3.0 Indeed,
when using lambda expressions, you can clean up this code considerably by using the lambda expression syntax
to replace the previous anonymous delegates I cover lambda expressions in Chapter 15
As a final extension method example for operations on the IList<T> type, consider how we could create an extension method to reverse the list and return a new IList<T> There are several ways one could consider doing this, and some are much more efficient than others However, I want to show you
an example that uses a form of recursion Consider the following Reverse<T> custom method
implementation:
Trang 8CHAPTER 14 ■ EXENTENSION METHODS
509
public static class CustomIterators
{
public static IList<T> Reverse<T>( this IList<T> theList ) {
var reverseList = new List<T>();
Func<IList<T>, List<T>> reverseFunc = null;
reverseFunc = delegate(IList<T> list) {
if( list != null ) {
If you’ve never encountered this style of coding, it can surely make your brain twist inside your
head The key to the work lies in the fact that there is a delegate defined that calls itself and captures
variables along the way.3 In the preceding code, the anonymous method is assigned to the reverseFunc variable And as you can see, the anonymous method body calls reverseFunc, or more accurately, itself!
In a way, the anonymous method captures itself! The trigger to get all the work done is in the last line of the Reverse<> method It initiates the chain of recursive calls to the anonymous method and then passes the resulting List<T> to the CreateList method, thus creating the reversed list
Those who pay close attention to efficiency are likely pointing out the inefficiency of creating a
temporary List<T> instance that is then passed to CreateList in Main After all, if the original list is
huge, creating a temporary list to just throw away moments later will put pressure on the garbage
collected heap, among other things For example, if the constructor to MyList<T> is made public, you can eliminate the temporary List<T> entirely and build the new MyList<T> using a captured variable as
shown here:
public static class CustomIterators
{
public static IList<T> Reverse<T>( this IList<T> theList ) {
var reverseList = new MyList<T>(default(T), null);
Func<IList<T>, MyList<T>> reverseFunc = null;
reverseFunc = delegate(IList<T> list) {
if( list.Tail != null ) {
reverseList = new MyList<T>( list.Head, reverseList );
reverseFunc( list.Tail );
}
return reverseList;
3 Computer science wonks like to call a delegate that captures variables a closure, which is a construct in which a
function is packaged with an environment (such as variables)
Trang 9CHAPTER 14 ■ EXTENSION METHODS
implementation of Reverse<T>, I instead pass the reference to the list I am building as an argument to each recursion of the anonymous method reverseFunc Why would you want to do this? By eliminating the captured variable reverseList, you eliminate the possibility that the reference could be
inadvertently changed outside of the scope of the anonymous method Therefore, my final example of the Reverse<T> method uses only the stack as a temporary storage location while building the new reversed list:
public static class CustomIterators
{
public static IList<T> Reverse<T>( this IList<T> theList ) {
Func<IList<T>, IList<T>, IList<T>> reverseFunc = null;
reverseFunc = delegate(IList<T> list, IList<T> result) {
if( list.Tail != null ) {
return reverseFunc( list.Tail, new MyList<T>(list.Head, result) );
■ Note This code uses the Func<> definition, which is a generic delegate that is defined in the System
namespace Using Func<> is a shortcut you can employ to avoid having to declare delegate types all over the place You use the Func<> type parameter list to declare what the parameter types (if any) and return type of the delegate are If the delegate you need has no return value, you can use the Action<> generic delegate type
The MyList<T> class used in the previous examples builds the linked list from the IEnumerable<T> type entirely before the MyList<T> object can be used I used a List<T> as the seed data, but I could have used anything that implements IEnumerable<T> to fill the contents of MyList<T> But what if
Trang 10CHAPTER 14 ■ EXENTENSION METHODS
511
IEnumerable<T> were an infinite iterator similar to the one created by CreateInfiniteList in the
“Operation Chaining” section of this chapter? If you fed the result of CreateInfiniteList to
MyList<T>.CreateList, you would have to kill the program forcefully or wait until your memory runs out
as it tries to build the MyList<T> If you are creating a library for general use that contains a type such as MyList<T>, which builds itself given some IEnumerable<T> type, you should do your best to accommodate all scenarios that could be thrown at you The IEnumerable<T> given to you could take a very long time to calculate each item of the enumeration For example, it could be enumerating over a database of live
data in which database access is very costly For an example of how to create the list in a lazy fashion, in which each node is created only when needed, check out Wes Dyer’s excellent blog, specifically the entry titled “Why all the love for lists?”4 The technique of lazy evaluation while iterating is a fundamental
feature of LINQ, which I cover in Chapter 16
The Visitor Pattern
The Visitor pattern, as described in the seminal pattern book Design Patterns: Elements of Reusable
Object-Oriented Software by the Gang of Four,5 allows you to define a new operation on a group of
classes without changing the classes Extension methods present a handy option for implementing the Visitor pattern
For example, consider a collection of types that might or might not be related by inheritance, and
imagine that you want to add functionality to validate instances of them at some point in your
application One option, although very unattractive, is to modify the public contract of all the types,
introducing a Validate method on each of them One might even jump to the conclusion that the easiest way to do it is to introduce a new base type that derives from System.Object, implements Validate as an abstract method, and then makes all the other types derive from the new type instead of System.Object That would be nothing more than a maintenance nightmare in the end
By now, you should agree that an extension method or a collection of extension methods will do the trick nicely Given a collection of unrelated types, you will probably implement a host of extension
methods But the beauty is that you don’t have to change the already defined types In fact, if they’re not your types to begin with, you cannot change them anyway Consider the following code:
public static void Validate( this String str ) {
// Do something to validate the String instance
4 You can find Wes Dyer’s blog titled “Yet Another Language Geek” at blogs.msdn.com/wesdyer/
5 Design Patterns: Elements of Reusable Object-Oriented Software, by Erich Gamma, Richard Helm, Ralph Johnson,
and John Vlissides (Boston, MA: Addison-Wesley Professional, 1995), is cited in the references at the end of this book
Trang 11CHAPTER 14 ■ EXTENSION METHODS
512
}
public static void Validate( this SupplyCabinet cab ) {
// Do something to validate the SupplyCabinet instance
Console.WriteLine( "Supply Cabinet Validated." );
}
public static void Validate( this Employee emp ) {
// Do something to validate the Employee instance
Console.WriteLine( "** Employee Failed Validation! **" );
static void Main() {
String data = "some important data";
SupplyCabinet supplies = new SupplyCabinet();
Employee hrLady = new Employee();
String with "some important data" Validated
Supply Cabinet Validated
** Employee Failed Validation! **
Trang 12CHAPTER 14 ■ EXENTENSION METHODS
513
In this example, it’s important to note that the visitors, in this case the extension methods named
Validate, must treat the instance that they are validating as black boxes By that I mean that they do not have the validation capabilities of a true instance method because only true instance methods have
access to the internal state of the objects Nevertheless, in this example, it might make sense to validate the instances from a client’s perspective
■ Note Keep in mind that if the extension methods are defined in the same assembly as the types they are
extended, they can still access internal members
Using generics and constraints, you can slightly extend the previous example and provide a generic form of the Validate extension method that can be used if the instance supports a well-known interface
In this case, the well-known interface is named IValidator Therefore, it would be nice to create a
special Validate method that will be called if the type implements the IValidator interface Consider the following code, which shows the changes marked in bold:
public static void Validate( this String str ) {
// Do something to validate the String instance
public static void Validate( this Employee emp ) {
// Do something to validate the Employee instance
Console.WriteLine( "** Employee Failed Validation! **" );
Trang 13CHAPTER 14 ■ EXTENSION METHODS
public void DoValidation() {
Console.WriteLine( "\tValidating SupplyCabinet" );
static void Main() {
String data = "some important data";
SupplyCabinet supplies = new SupplyCabinet();
Employee hrLady = new Employee();
public class MyApplication
{
static void Main() {
String data = "some important data";
SupplyCabinet supplies = new SupplyCabinet();
Employee hrLady = new Employee();
data.Validate();
// Force generic version
supplies.Validate<SupplyCabinet>();
Trang 14CHAPTER 14 ■ EXENTENSION METHODS
methods can cause confusion when defined inappropriately, so we looked at some caveats to avoid I
showed you how they can be used to create useful things such as iterators (IEnumerable<T> types) on
containers that are not enumerable by default Even for types that do have enumerators, you can define enumerators that iterate in a custom way As you’ll see in Chapter 15, when they are combined with
lambda expressions, extension methods provide a certain degree of expressiveness that is extremely
useful While showing how to create custom iterators, I took a slight detour (using anonymous functions rather than lambda expressions) to show you the world of functional programming that the features
added to C# 3.0 unlock The code for those examples will become much cleaner when you use lambda
expressions instead of anonymous methods
In the next chapter, I’ll introduce you to lambda expressions, which really make functional
programming in C# syntactically succinct Additionally, they allow you to convert a functional
expression into either code or data in the form of IL code or an expression tree, respectively
Trang 15CHAPTER 14 ■ EXTENSION METHODS
516
Trang 16C H A P T E R 15
■ ■ ■
517
Lambda Expressions
Most of the new features of C# 3.0 opened up a world of expressive functional programming to the C#
programmer Functional programming, in its pure form, is a programming methodology built on top of
immutable variables (sometimes called symbols), functions that can produce other functions, and
recursion, just to name a few of its foundations Some prominent functional programming languages
include Lisp, Haskell, F#,1 and Scheme.2 However, functional programming does not require a pure
functional language, and one can use and implement functional programming disciplines in
traditionally imperative languages such as the C-based languages (including C#) The features added in C# 3.0 transformed the language into a more expressive hybrid language in which both imperative and functional programming techniques can be utilized in harmony Lambda expressions are arguably the biggest piece of this functional programming pie
Introduction to Lambda Expressions
Using lambda expressions, you can succinctly define function objects for use at any time C# has always supported this capability via delegates, whereby you create a function object (in the form of a delegate) and wire it up to the backing code at the time of creation Lambda expressions join these two actions—creation and connection—into one expressive statement in the code Additionally, you can easily
associate an environment with function objects using a construct called a closure A functional is a
function that takes functions in its parameter list and operates on those functions, possibly even
returning another function as the result For example, a functional could accept two functions, one
performing one mathematical operation and the other performing a different mathematical operation, and return a third function that is a composite function built from the two Lambda expressions provide
a more natural way to create and invoke functionals
In simple syntactic terms, lambda expressions are a syntax whereby you can declare anonymous
functions (delegates) in a more fluid and expressive way At the same time, they are very much more
than that, as you will see Just about every use of an anonymous method can be replaced with a lambda
1 F# is an exciting new functional programming language for the NET Framework For more information, I invite you
to read Robert Pickering’s Foundations of F# (Berkeley, CA: Apress, 2007)
2 One of the languages that I use often is C++ Those of you that are familiar with metaprogramming in C++ are
definitely familiar with functional programming techniques If you do use C++ and you’re curious about
metaprogramming, I invite you to check out David Abrahams’ and Alexey Gurtovoy’s most excellent book C++
Template Metaprogramming (Boston: Addison-Wesley Professional, 2004)
Trang 17CHAPTER 15 ■ LAMBDA EXPRESSIONS
518
expression That said, there’s no reason you can’t utilize functional programming techniques in C# 2.03
At first, the syntax of lambda expressions might take some time to get used to Overall, the syntax is very straightforward when you are looking at a lambda expression all by itself However, when embedded in code, they can be a little tricky to decipher and it might take some time to get used to their syntax Lambda expressions really take two forms The form that most directly replaces anonymous
methods in syntax includes a statement block within braces I like to refer to these as lambda statements
These lambda statements are a direct replacement for anonymous methods Lambda expressions, on the other hand, provide an even more abbreviated way to declare an anonymous method and do not require code within braces nor a return statement Both types of lambda expressions can be converted
to delegates However, lambda expressions without statement blocks offer something truly impressive You can convert them into expression trees based on the types in the System.Linq.Expressions
namespace In other words, the function described in code is turned into data I cover the topic of creating expression trees from lambda expressions in the section titled “Expression Trees” later in this chapter
Lambda Expressions and Closures
First, let’s look at the simpler form of lambda expressions; that is, the ones without a statement block As mentioned in the previous section, a lambda expression is a shorthand way of declaring a simple anonymous method The following lambda expression can be used as a delegate that accepts one parameter and returns the result of performing division by 2 on that parameter:
x => x / 2
What this says is “take x as a parameter and return the result of following operation on x.” Notice that the lambda expression is devoid of any type information It does not mean that the expression is typeless Instead, the compiler will deduce the type of the argument x and the type of the result depending on the context where it is used It means that if you are assigning a lambda expression to a delegate, the types of the delegate definition are used to determine the types within the lambda expression The following code shows what happens when a lambda expression is assigned to a delegate type:
using System;
using System.Linq;
public class LambdaTest
{
static void Main() {
Func<int, double> expr = x => x / 2;
3 I covered some examples of functional programming with anonymous methods in Chapter 14
Trang 18CHAPTER 15 ■ LAMBDA EXPRESSIONS
519
an int and returns a double When the compiler assigns the lambda expression to the expr variable, it
uses the type information of the delegate to determine that the type of x must be int, and the type of the return value must be double
Now, if you execute that code, you’ll notice that the result is not entirely accurate That is, the result has been rounded This is expected because the result of x/2 is represented as an int, which is then cast
to a double You can fix this by specifying different types in the delegate declaration, as shown here:
using System;
using System.Linq;
public class LambdaTest
{
static void Main() {
Func<double, double> expr = (double x) => x / 2;
int someNumber = 9;
Console.WriteLine( "Result: {0}", expr(someNumber) );
}
}
For the sake of demonstration, this lambda expression has what’s called an explicitly typed
parameter list, and in this case, x is declared as type double Also notice that the type of expr is now
Func<double, double> rather than Func<int, double> The compiler requires that any time you use a
typed parameter list in a lambda expression and assign it to a delegate, the delegate’s argument types
must match exactly However, because an int is explicitly convertible to a double, you can pass
someNumber to expr at call time as shown
■ Note When using typed parameter lists, notice that the parameter list must be enclosed in parentheses
Parentheses are also required when declaring a delegate that accepts either more than one parameter or no
parameters, as I’ll show later on In fact, you can use parentheses at any time; they are optional in lambda
expressions of only one implicitly typed parameter
When the lambda expression is assigned to a delegate, the return type of the expression is generally derived from the argument types So, in the following code statement, the return type of the expression
is double because the inferred type of the parameter x is double:
Func<double, int> expr = (x) => x / 2; // Compiler Error!!!!
However, because double is not implicitly convertible to int, the compiler will complain:
error CS1662: Cannot convert 'lambda expression' to
delegate type 'System.Func<double,int>' because some of the return
Trang 19CHAPTER 15 ■ LAMBDA EXPRESSIONS
520
types in the block are not implicitly convertible to the delegate return
type
You can “fix” this by casting the result of the lambda expression body to int:
Func<double, int> expr = (x) => (int) x / 2;
■ Note Explicit types in lambda expression parameter lists are required if the delegate you are assigning them to
has out or ref parameters One could argue that fixing the parameter types explicitly within a lambda expression defeats some of the elegance of their expressive power It definitely can make the code harder to read
Now I want to show you a simple lambda expression that accepts no parameters:
static void WriteStream( Func<int> generator ) {
for( int i = 0; i < 10; ++i ) {
Trang 20CHAPTER 15 ■ LAMBDA EXPRESSIONS
521
public class LambdaTest
{
static void Main() {
var teamMembers = new List<string> {
Func<string, string, bool> predicate ) {
foreach( var member in members ) {
if( predicate(member, firstName) ) {
Closures in C# 1.0
Back in the “good old days” of C# 1.0, creating closures was a painful process indeed, and one needed to
do something like the following:
public delegate int IncDelegate();
public IncDelegate GetDelegate() {
return new IncDelegate( IncrementFunction );
}
Trang 21CHAPTER 15 ■ LAMBDA EXPRESSIONS
static void WriteStream( MyClosure.IncDelegate incrementor ) {
for( int i = 0; i < 10; ++i ) {
What a lot of work! And on top of that, it sure makes for some hard-to-follow code
■ Note You might be wondering why I used a pointer in the preceding longhand example, thus forcing one to
compile using the /unsafe compiler option The reason was simply to emphasize the fact that the captured variable can be changed out of band from the code consuming it When the C# compiler captures a variable in a closure, it does something similar, but instead of using a pointer to the captured variable, it instead initializes a
4 The intricacies of unsafe coding in C# are outside the scope of this book I encourage you to reference the MSDN documentation for further details
Trang 22CHAPTER 15 ■ LAMBDA EXPRESSIONS
523
public field of the generated class that implements the closure with a reference to the captured variable or a copy
if the captured variable is a value type However, any code that attempts to modify the captured variable outside the scope of the closure modifies the copy within the closure object because, after all, it is a public field Design wonks might cry foul because public fields are considered evil However, remember that this is part of the
compiler implementation In fact, the class the compiler generates is “unspeakable,” meaning that you cannot
instantiate an instance of it in C# code because the name itself, if typed in code, will generate a syntax error I
invite you to inspect the way the compiler generates closures by opening the compiled code within Intermediate Language Disassembler (ILDASM)
Closures in C# 2.0
In C# 2.0, anonymous methods were introduced to reduce the burden I just described However, they
are not as functionally expressive as lambda expressions because they still carry the old imperative
programming style with them and require parameter types in the parameter list Additionally, the
anonymous method syntax is rather bulky For good measure, the following shows how the previous
example would be implemented using anonymous methods, so you can see the difference in syntax
from lambda expressions:
static void WriteStream( Func<int> counter ) {
for( int i = 0; i < 10; ++i ) {
I have bolded the differences between this example and the original lambda expression example
It’s definitely much cleaner than the way you would have implemented it in the C# 1.0 days However,
it’s still not as expressive and succinct as the lambda expression version Using lambda expressions, you have an elegant means of defining potentially very complex functions that can even be built by
assembling together other functions
Trang 23CHAPTER 15 ■ LAMBDA EXPRESSIONS
524
■ Note In the previous code example, you likely noticed the implications of referencing the counter variable within the lambda expression After all, counter is actually a local variable within the scope of Main, yet within the scope of WriteStream it is referenced while invoking the delegate In the Chapter 10 section “Beware the Captured Variable Surprise,” I described how you can do the same thing with anonymous methods In functional
programming lingo, this is called a closure In essence, any time a lambda expression incorporates the
environment around it, a closure is the result As I’ll show in a following section, “Closures (Variable Capture) and Memoization,” closures can be very useful However, when used inappropriately, they can create some nasty surprises
Lambda Statements
All the lambda expressions I have shown so far have been purely of the expression type Another type of
lambda expression is one I like to call a lambda statement It is similar in form to the lambda expressions
of the previous section except that it is composed of a compound statement block within curly braces Because of that, a lambda with statement blocks must have a return statement In general, all lambda expressions shown in the previous section can be converted to a lambda with a statement block simply
by surrounding the expression with curly braces after prefixing the right side with a return statement For example, the following lambda expression:
System.Linq.Expressions.Expression<T> I’ll discuss expression trees in the next section
■ Note The big difference between lambdas with statement blocks and anonymous methods is that anonymous
methods must explicitly type their parameters, whereas the compiler can infer the types of the lambda based on context in almost all cases The abbreviated syntax offered by lambda expressions fosters a more functional programming thought process and approach
Expression Trees
So far, I have shown you lambda expressions that replace the functionality of delegates If I stopped there, I would be doing you a great disservice That’s because the C# compiler also has the capability to convert lambda expressions into expression trees based on the types in the System.Linq.Expressions
Trang 24CHAPTER 15 ■ LAMBDA EXPRESSIONS
525
namespace I’ll explain why this is such a great thing in a later section, “Functions as Data.” For example, you’ve already seen how you can convert a lambda expression into a delegate as shown here:
Func<int, int> func1 = n => n+1;
In this line of code, the expression is converted into a delegate that accepts a single int parameter and returns an int However, check out the following modification:
Expression<Func<int, int>> expr = n => n+1;
This is really cool! The lambda expression, instead of being converted into a callable delegate, is
converted into a data structure that represents the operation The type of the expr variable is
Expression<T>, where T is replaced with the type of delegate the lambda can be converted to The
compiler notices that you are trying to convert the lambda expression into an
Expression<Func<int,int>> instance and generates all the code internally to make it happen At some
point later in time, you can then compile the expression into a usable delegate as shown in the next
static void Main() {
Expression<Func<int, int>> expr = n => n+1;
Func<int, int> func = expr.Compile();
for( int i = 0; i < 10; ++i ) {
Console.WriteLine( func(i) );
}
}
}
The line in bold shows the step at which the expression is compiled into a delegate If you think
about it a little bit, you might quickly start imagining how you could modify this expression tree or even combine multiple expression trees to create more complex expression trees prior to compiling them
One could even define a new expression language or implement a parser for an already existing
expression language In fact, the compiler acts as an expression parser when you assign a lambda
expression into an Expression<T> type instance Behind the scenes, it generates the code to build the
expression tree and if you use ILDASM or Reflector to look at the generated code, you can see it in
static void Main() {
var n = Expression.Parameter( typeof(int), "n" );
Trang 25CHAPTER 15 ■ LAMBDA EXPRESSIONS
526
var expr = Expression<Func<int,int>>.Lambda<Func<int,int>>(
Expression.Add(n, Expression.Constant(1)),
n );
Func<int, int> func = expr.Compile();
for( int i = 0; i < 10; ++i ) {
following:
var n = Expression.Parameter( typeof(int), "n" );
■ Note In these examples, I am using implicitly typed variables to save myself a lot of typing and to reduce clutter
for readability Remember, the variables are still strongly typed The compiler simply infers their type at compile time rather than requiring you to provide the type
This line of code says that we need an expression to represent a variable named n that is of type int Remember that in a plain lambda expression, this type can be inferred based upon the delegate type provided
Now, we need to construct a BinaryExpression instance that represents the addition operation, as shown next:
Expression implementation to decide which type we really need
Trang 26CHAPTER 15 ■ LAMBDA EXPRESSIONS
527
■ Note If you look up BinaryExpression, UnaryExpression, ParameterExpression, and so on in the MSDN
documentation, you will notice that there are no public constructors on these types Instead, you create instances
of Expression derived types using the Expression type, which implements the factory pattern and exposes static methods for creating instances of Expression derived types
Now that you have the BinaryExpression, you need to use the Expression.Lambda<> method to bind the expression (in this case, n+1) with the parameters in the parameter list (in this case, n) Notice that in the example I use the generic Lambda<> method so that I can create the type Expression<Func<int,int>> Using the generic form gives the compiler more type information to catch any errors I might have
introduced at compile time rather than let those errors bite me at run time
One more point I want to make that demonstrates how expressions represent operations as data is with the Expression Tree Debugger Visualizer in Visual Studio 2010 If you execute the previous example within the Visual Studio Debugger, once you step past the point where you assign the expression into the expr variable, you will notice that in either the “Autos” or “Locals” windows, the expression is parsed and displayed as {n => (n + 1)} even though it is of type
System.Linq.Expressions.Expression<System.Func<int,int>> Naturally, this is a great help while
creating complicated expression trees
■ Note If I had used the nongeneric version of the Expression.Lambda method, the result would have been an
instance of LambdaExpression rather than Expression LambdaExpression also implements the Compile
method; however, instead of a strongly typed delegate, it returns an instance of type Delegate Before you can
invoke the Delegate instance, you must cast it to the specific delegate type; in this case, Func<int, int> or
another delegate with the same signature, or you must call DynamicInvoke on the delegate Either one of those
could throw an exception at run time if you have a mismatch between your expression and the type of delegate
you think it should generate
Operating on Expressions
Now I want to show you an example of how you can take an expression tree generated from a lambda
expression and modify it to create a new expression tree In this case, I will take the expression (n+1) and turn it into 2*(n+1):
Trang 27CHAPTER 15 ■ LAMBDA EXPRESSIONS
Func<int, int> func = expr.Compile();
for( int i = 0; i < 10; ++i ) {
System.InvalidOperationException: Lambda Parameter not in scope
There are many classes derived from the Expression class and many static methods for creating instances of them and combining other expressions It would be monotonous for me to describe them all here Therefore, I recommend that you refer to the MSDN Library documentation regarding the System.Linq.Expressions namespace for all the fantastic details
Functions as Data
If you have ever studied functional languages such as Lisp, you might notice the similarities between expression trees and how Lisp and similar languages represent functions as data structures Most people encounter Lisp in an academic environment, and many times concepts that one learns in academia are not directly applicable to the real world But before you eschew expression trees as merely an academic exercise, I want to point out how they are actually very useful
As you might already guess, within the scope of C#, expression trees are extremely useful when applied to LINQ I will give a full introduction to LINQ in Chapter 16, but for our discussion here, the most important fact is that LINQ provides a language-native, expressive syntax for describing operations
on data that are not naturally modeled in an object-oriented way For example, you can create a LINQ expression to search a large in-memory array (or any other IEnumerable type) for items that match a certain pattern LINQ is extensible and can provide a means of operating on other types of stores, such
as XML and relational databases In fact, out of the box, C# supports LINQ to SQL, LINQ to Dataset, LINQ to Entities, LINQ to XML, and LINQ to Objects, which collectively allow you to perform LINQ operations on any type that supports IEnumerable
So how do expression trees come into play here? Imagine that you are implementing LINQ to SQL to query relational databases The user’s database could be half a world away, and it might be very
expensive to perform a simple query On top of that, you have no way of judging how complex the user’s
Trang 28CHAPTER 15 ■ LAMBDA EXPRESSIONS
entirety on the server
Expression trees give you this important capability Then, when you are finished operating on the
data, you can translate the expression tree into the final executable operation via a mechanism such as the LambdaExpression.Compile method and go Had the expression only been available as IL code from the beginning, your flexibility would have been severely limited I hope now you can appreciate the true power of expression trees in C#
Useful Applications of Lambda Expressions
Now that I have shown you what lambda expressions look like, let’s consider some of the things you can
do with them You can actually implement most of the following examples in C# using anonymous
methods or delegates However, it’s amazing how a simple syntactic addition to the language can clear the fog and open up the possibilities of expressiveness
Iterators and Generators Revisited
I’ve described how you can create custom iterators with C# in a couple of places in this book already.5
Now I want to demonstrate how you can use lambda expressions to create custom iterators The point I want to stress is how the code implementing the algorithm, in this case the iteration algorithm, is then factored out into a reusable method that can be applied in almost any scenario
■ Note Those of you who are also C++ programmers and familiar with using the Standard Template Library (STL)
will find this notion a familiar one Most of the algorithms defined in the std namespace in the <algorithm>
header require you to provide predicates to get their work done When the STL arrived on the scene back in the
early 1990s, it swept the C++ programming community like a refreshing functional programming breeze
I want to show how you can iterate over a generic type that might or might not be a collection in the strict sense of the word Additionally, you can externalize the behavior of the iteration cursor as well as how to access the current value of the collection With a little thought, you can factor out just about
everything from the custom iterator creation method, including the type of the item stored, the type of the cursor, the start state of the cursor, the end state of the cursor, and how to advance the cursor All
5 Chapter 9 introduces iterators via the yield statement, and Chapter 14 expanded on custom iterators in the section titled “Borrowing from Functional Programming.”
Trang 29CHAPTER 15 ■ LAMBDA EXPRESSIONS
public static IEnumerable<TItem>
MakeCustomIterator<TCollection, TCursor, TItem>(
this TCollection collection,
TCursor cursor,
Func<TCollection, TCursor, TItem> getCurrent,
Func<TCursor, bool> isFinished,
Func<TCursor, TCursor> advanceCursor) {
while( !isFinished(cursor) ) {
yield return getCurrent( collection, cursor );
cursor = advanceCursor( cursor );
static void Main() {
var matrix = new List<List<double>> {
(coll, cur) => coll[cur[0]][cur[1]],
(cur) => cur[0] > 2 || cur[1] > 2,
(cur) => new int[] { cur[0] + 1,
MakeCustomIterator<> are delegate types that it uses to determine how to iterate over the collection