Chapter 3. Expressing Anonymous Methods with Lambda Expressions

We covered delegates in the previous chapter, as it was a pre-requisite for understanding anonymous methods and lambda expressions, the subject of the current chapter. By using an anonymous method, we can create a delegate instance with no need to have a separate method. By using the lambda expression, we can create a shorthand syntax for the anonymous method. In this chapter, we are going to dig up the anonymous methods as well as Lambda expressions. The topics in this chapter are as follows:

  • Applying delegate to create and use anonymous methods
  • Transformation of anonymous methods to lambda expressions
  • Understanding expression trees and its relation to lambda
  • Subscribing for events using lambda expressions
  • Elaborating the benefit of lambda expressions in the use of functional programming

Getting to know anonymous methods

In the previous chapter, we already discussed how to declare a delegate using named methods. When using named methods, we've have to create a method first, give it a name, and then associate it with the delegate. To refresh our memory, a simple delegate declaration associated with a named method is provided as follows:

delegate void DelDelegate(int x); 
void DoSomething(int i) { /* Implementation */ } 
DelDelegate d = DoSomething; 

From the preceding code, we simply create a delegate data type named DelDelegate, and we also create a method named DoSomething. After we have a named method, we can associate the delegate with the method. Fortunately, anonymous methods were announced in C# 2.0 to ease the use of delegates. They provide us with a shortcut to create a simple and short method that will be used once. The syntax to declare an anonymous method is as follows:

delegate([parameters]) { implementation } 

The explanation for each element of the anonymous method syntax is as follows:

  • Delegate: The keyword we need in order to initialize a delegate.
  • Parameters: The list of parameters that the method we assign to this delegate takes.
  • Implementation: The code that will be executed by the method. It can apply a return statement if the method needs to return a value.

From the preceding syntax, we can see that an anonymous method is a method that doesn't have a name. We just need to define the arguments and the implementation of the method.

Creating anonymous methods

For further discussion, let's create a simple anonymous method, which we can find in the SimpleAnonymousMethods.csproj project, as follows:

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

We now have an anonymous method we assign to the delegate displayMessageDelegate delegate. We create the displayMessageDelegate delegate using the Func built-in delegate, which takes only one string argument and a return string value as well. If we need to run the anonymous method, we can invoke the delegate as follows:

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

After running the preceding code, we will get the following output on the console:

Creating anonymous methods

As we can see in the output console window, we have successfully invoked the anonymous method by calling the delegate name. Now, let's go back to the previous chapter to use some code from there and refactor it to an anonymous method. We are going to refactor the code of SimpleDelegates.csproj, which we've discussed in the previous chapter. The following is the declaration of anonymous methods, and it can be found in the SimpleDelegatesRefactor.csproj project:

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

We have two anonymous methods in our preceding code. We also use the Func delegate, the built-in delegate we discussed in the previous chapter. To invoke the methods, we can invoke the delegate name as follows:

public partial class Program 
{ 
  static void Main(string[] args) 
  { 
    int i = AreaRectangleDelegate(1, 2); 
    int j = AreaSquareDelegate(2, 3); 
    Console.WriteLine("i = " + i); 
    Console.WriteLine("j = " + j); 
  } 
} 

If we run the project, we will get an output like this:

Creating anonymous methods

Compared to the code in the SimpleDelegates.csproj project, our code in the preceding SimpleDelegatesRefactor.csproj project becomes simpler and shorter since we don't need to declare the delegate. The delegate is declared simultaneously with the creation of an anonymous method, such as the following code snippet:

private static Func<int, int, int> AreaRectangleDelegate = 
  delegate (int a, int b) 
{ 
  return a * b; 
}; 

Here is the code we used in our previous chapter, named SimpleDelegates.csproj:

public partial class Program 
{ 
  private delegate int AreaCalculatorDelegate(int x, int y); 
  static int Square(int x, int y) 
  { 
    return x * y; 
  } 
} 

Using anonymous delegation , we have simplified our code compared to the code produced in the previous chapter.

Using an anonymous method as an argument

We have now executed an anonymous method. However, the anonymous method can also be passed to a method as a parameter. Let's look at the following code, which we can find in the AnonymousMethodAsArgument.csproj project:

public partial class Program 
{ 
  private static bool IsMultipleOfSeven(int i) 
  { 
    return i % 7 == 0; 
  } 
} 

First, we have a method named FindMultipleOfSeven in this project. The method will be passed to the argument of the following method:

public partial class Program 
{ 
  private static int FindMultipleOfSeven(List<int> numList) 
  { 
    return numList.Find(IsMultipleOfSeven); 
  } 
} 

Then, we call the FindMultipleOfSeven() method from the following method:

public partial class Program 
{ 
  private static void PrintResult() 
  { 
    Console.WriteLine( 
      "The Multiple of 7 from the number list is {0}", 
      FindMultipleOfSeven(numbers)); 
  } 
} 

We can also define the following List variable to be passed to the FindMultipleOfSeven() method argument:

public partial class Program 
{ 
  static List<int> numbers = new List<int>() 
  { 
    54, 24, 91, 70, 72, 44, 61, 93, 
    73, 3, 56, 5, 38, 60, 29, 32, 
    86, 44, 34, 25, 22, 44, 66, 7, 
    9, 59, 70, 47, 55, 95, 6, 42 
  }; 
} 

If we invoke the PrintResult() method, we will get the following output:

Using an anonymous method as an argument

The goal of the preceding program is to find a number that is multiplied by seven from the number list. And since 91 is the first number that meet this criteria, the FindMultipleOfSeven() method returns that number.

Inside the FindMultipleOfSeven() method, we can find the Find() method passing the IsMultipleOfSeven() method as an argument, as shown in the following code snippet:

return numList.Find(IsMultipleOfSeven); 

We can, if we want, replace this method with the anonymous method, as follows:

public partial class Program 
{ 
  private static int FindMultipleOfSevenLambda( 
    List<int> numList) 
  { 
    return numList.Find( 
      delegate(int i) 
      { 
        return i % 7 == 0; 
      } 
    ); 
  } 
} 

We now have the FindMultipleOfSevenLambda() method, which invokes the Find() method and passes the anonymous method to the method argument. Since we have passed the anonymous method, we don't need the FindMultipleOfSeven() method any longer. We can invoke the FindMultipleOfSevenLambda() method using the PrintResultLambda() method, as follows:

public partial class Program 
{ 
  private static void PrintResultLambda() 
  { 
    Console.WriteLine( 
      "({0}) The Multiple of 7 from the number list is {1}", 
      "Lambda", 
      FindMultipleOfSevenLambda(numbers)); 
  } 
} 

We will get the following output we after we have executed the PrintResultLambda() method:

Using an anonymous method as an argument

As we can see from the output window, we still retrieve 91 as a result of a number multiplication of 7. However, we have successfully passed the anonymous method as the method argument.

Writing anonymous methods - some guidelines

When writing anonymous methods, here are some things that we should keep in mind:

  • An anonymous method has no return type in its declaration. Consider the following code snippet:
            delegate (int a, int b) 
            { 
              return a * b; 
            }; 
    

    Note

    In the preceding delegate declaration, we don't find the return type, although we find the return keyword in the method implementation. This is because the compiler infers the return type based on the delegate signature.

  • We have to match the declaration of the delegate's signature with the method's argument. This will be similar to assigning a named method to a delegate. Let's take a look at the following code snippet:
            private static Func<int, int, int> AreaRectangleDelegate = 
              delegate (int a, int b) 
            { 
              return a * b; 
            }; 
    

    Note

    In the preceding code snippet, we declare a delegate that takes two int arguments and returns an int value. Refer to the delegate signature; we use the same signature when declaring the anonymous method.

  • We are not allowed to declare variables whose names conflict with the variables of the anonymous method that is declared. Take a look at the following code snippet:
            public partial class Program 
            { 
              private static void Conflict() 
              { 
                for (int i = 0; i < numbers.Count; i++) 
                { 
                  Action<int> actDelegate = delegate(int i) 
                  { 
                    Console.WriteLine("{0}", i); 
                  }; 
                  actDelegate(i); 
                } 
              } 
            } 
    

Note

We will never be able to compile the preceding code since we declare the variable i twice both in Conflict()method and in actDelegate delegate.

Advantages of the anonymous methods

Here are some advantages of using anonymous methods:

  • Since we do not attach a name to a method, they are a good solution if we want to invoke the method only once.
  • We can write the code in place rather than writing the logic in other parts of a code.
  • We don't need to declare the return type of the anonymous method since it will be inferred from the signature of the delegate that is assigned to the anonymous method.
  • We can access local variables of the outer method from the anonymous method. Outer variables are captured inside the anonymous method.
  • We do not need to create a named method for snippets of logic that are invoked once.
..................Content has been hidden....................

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