Lambda expressions

We now have an idea that anonymous methods can help us create a simple and short method. However, in C# 3.0, lambda expressions were announced in order to complement anonymous methods in providing a shorthand notation to create anonymous methods. In fact, lambda expressions become the preferred way when writing new code.

Now, let's examine the simplest lambda expression syntax, as follows:

([parameters]) => expression; 

In the lambda expression syntax, we only find two elements, which are parameters and expression. Like any method, a lambda expression has an argument symbolized by parameters. The implementation of the lambda expression is symbolized by the expression. We can also omit the parenthesis of parameters if only one parameter is required.

Let's create a simple lambda expression, which we can find in the SimpleLambdaExpression.csproj project, as follows:

public partial class Program 
{ 
  static Func<string, string> displayMessageDelegate = 
    str => String.Format(Message: {0}", str); 
} 

In the preceding code, we declare the displayMessageDelegate delegate and assign it to the Func delegate using a lambda expression. Similar to the method in the SimpleDelegates.csproj project, in order to invoke the delegate, we use the following code:

public partial class Program 
{ 
  static void Main(string[] args) 
  { 
    Console.WriteLine( 
      displayMessageDelegate( 
      "A simple lambda expression sample.")); 
  } 
} 

We call the displayMessageDelegate delegate like a method name. The output will be sent to the console, as follows:

Lambda expressions

Now, let's compare the method declaration between an anonymous method in SimpleAnonymousMethods.csproj and a lambda expression in the SimpleLambdaExpression.csproj project:

static Func<string, string> displayMessageDelegate = 
  delegate (string str) 
{ 
  return String.Format("Message: {0}", str); 
}; 

The preceding code snippet is an anonymous method declaration that is shorter and simpler than a named method declaration.

static Func<string, string> displayMessageDelegate = 
  str => String.Format("Message: {0}", str); 

The preceding code snippet is a lambda expression declaration that is shorter and simpler than an anonymous method. The lambda expressions are brief compared to anonymous methods.

Transforming an anonymous method to a lambda expression

Now, let's discuss the transformation of an anonymous method to a lambda expression. We have the following anonymous method:

delegate (string str) 
{ 
  return String.Format("Message: {0}", str); 
}; 
And we want to transform it to a lambda expression, as follows:
str => String.Format("Message: {0}", str); 

First, we take out the delegate keyword since we don't need it anymore; so, the code will be as follows:

(string str) 
{ 
  return String.Format("Message: {0}", str); 
}; 

Then, we supersede the curly braces with a => lambda operator in order to make it the inline lambda expression:

(string str) => return String.Format("Message: {0}", str); 

We can also remove the return keyword since it is only a single line code that returns a value. The code will be as follows:

(string str) => String.Format("Message: {0}", str); 

Since the preceding syntax is now an expression instead of a complete statement, the semicolon can be removed from the preceding code and the code will be as follows:

(string str) => String.Format("Message: {0}", str); 

The preceding expression is a valid lambda expression. However, we can simplify the code more in order to take advantage of the lambda expression. The code will be as follows:

(str) => String.Format("Message: {0}", str); 

Since we have taken out string data type, we can now take out the parenthesis as well:

str => String.Format("Message: {0}", str); 

The preceding syntax is our final lambda expression. As we can see, now, our code becomes more readable because of its simplicity.

Note

The parenthesis in the parameters list of lambda expressions can be omitted if it contains only one argument.

Using lambda expressions, we can actually create delegates and expression tree types in anonymous methods. Now, let's find out the difference between these two types in the upcoming topics.

Creating a delegate type using lambda expresions

We discussed lambda expressions in a delegate type when we created code in the SimpleLambdaExpression.csproj project. Now, let's create another project name in order to discuss this by referring to the following code:

public partial class Program 
{ 
  private static Func<int, int, int> AreaRectangleDelegate = 
    (a, b) => a * b; 
  private static Func<int, int, int> AreaSquareDelegate = 
    (x, y) => x * y; 
} 

Again, we refactor the SimpleDelegatesRefactor.csproj project and replace the anonymous method with a lambda expression. As we can see, the lambda expression is assigned to a variable typed delegate. Here, we create a lambda expression in a delegate type. We can use the Main() method we had used in the SimpleDelegatesRefactor.csproj project to invoke AreaRectangleDelegate and AreaSquareDelegate. The result of the two projects will be completely the same.

Expression trees and lambda expressions

Besides creating a delegate, we can create expression trees, which are data structures which represents the expression elements (expr, term, factor) as a tree. By traversing the tree, one can interpret the expression trees or we can mutate a node in the tree for transforming the code. In compiler parlance, expressions trees are called abstract syntax trees (AST).

Now, let's take a look at the following code snippet in order to assign a lambda expression to the delegate that we discussed earlier:

Func<int, int, int> AreaRectangleDelegate = 
  (a, b) => a * b; 

As we can see, there are three sections in the preceding statement. They are as follows:

  • A variable typed delegate declaration: Func<int, int, int> AreaRectangleDelegate
  • An equal operator: =
  • A lambda expression: (a, b) => a * b

We are going to translate the preceding code statement into data. To achieve this goal, we need to create an instance of the Expression<T> type, and T is delegate type. The Expression<T> type is defined in the System.Linq.Expressions namespace. After using this namespace in the project, we can translate our preceding code into an expression tree, as follows:

public partial class Program 
{ 
  static void Main(string[] args) 
  { 
    Expression<Func<int, int, int>> expression = 
      (a, b) => a * b; 
  } 
} 

We have converted our preceding delegate lambda expression into the expression tree declared to be of type Expression<T>. The variable expression in the preceding code is not executable code but a data structure called an expression tree. There are four essentials properties in the Expression<T> class that we will discuss in detail. They are as follows:

  • Body: This contains the body of the expression
  • Parameters: This contain the parameters of the lambda expression
  • NodeType: This contains the ExpressionType type of node in the tree
  • Type: This contains the static type of the expression

Now, let's add a breakpoint in the expression variable and run the debugging process by pressing F5 in the LambdaExpressionInExpressionTree.csproj project. After executing the expression declaration line, we can take a peek at the variable window in the Visual Studio IDE, and we will get the following screenshot:

Expression trees and lambda expressions

From the preceding screenshot, we have a Body property containing {(a * b)}, NodeType containing Lambda, Type containing the Func delegate with three templates, and are two parameters. If we expand the Body information in the variable window, we will get a result similar to what is shown in the following screenshot:

Expression trees and lambda expressions

From the preceding screenshot, we can see that we have the Left property containing {a} and the Right property containing {b}. Using these properties, we can also explore the body of expression tree programmatically. The following code is the exploreBody() method, which will explore the properties of Body:

public partial class Program 
{ 
  private static void exploreBody( 
    Expression<Func<int, int, int>> expr) 
  { 
    BinaryExpression body = 
      (BinaryExpression)expr.Body; 
    ParameterExpression left = 
      (ParameterExpression)body.Left; 
    ParameterExpression right = 
      (ParameterExpression)body.Right; 
    Console.WriteLine(expr.Body); 
    Console.WriteLine( 
      "	The left part of the expression: {0}
" + 
      "	The NodeType: {1}
" + 
      "	The right part: {2}
" + 
      "	The Type: {3}
", 
      left.Name, 
      body.NodeType, 
      right.Name, 
      body.Type); 
  } 
} 

If we run the preceding exploreBody() method, we will get the following output:

Expression trees and lambda expressions

In the preceding  code, we access the Body properties of Expression<T> programmatically. We need to create a BinaryExpression data type in order to get the Body content, and ParameterExpression in order to get the Left and Right properties content. The code snippet for the BinaryExpression and ParameterExpression data is as follows:

BinaryExpression body = 
  (BinaryExpression)expr.Body; 
ParameterExpression left = 
  (ParameterExpression)body.Left; 
ParameterExpression right = 
  (ParameterExpression)body.Right; 

We have successfully created a data structure from the code in the expression tree. We can, if we want, convert this data back into code by compiling the expression. The expression we have is as follows:

Expression<Func<int, int, int>> expression = 
  (a, b) => a * b; 

So, we can compile the expression and run the code in the expression using the following compilingExpr() method:

public partial class Program 
{ 
  private static void compilingExpr( 
    Expression<Func<int, int, int>> expr) 
  { 
    int a = 2; 
    int b = 3; 
    int compResult = expr.Compile()(a, b); 
    Console.WriteLine( 
      "The result of expression {0}"+ 
      " with a = {1} and b = {2} is {3}", 
      expr.Body, 
      a, 
      b, 
      compResult); 
  } 
} 

If we run the compilingExpr() method, the following output will be displayed on the console window:

Expression trees and lambda expressions

As we can see, we have compiled the expression using the Compile() method in the expression class, as follows:

int compResult = expr.Compile()(a, b); 

The expr.Compile() method produces a delegate of type Func<int, int, int> in accordance with the type of the expression. We give the Compile() method the arguments a and b based on its signature, then it returns the int value.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset