Friday 11 April 2014

Anonymous methods and Lamda Expression

The concept of anonymous method was introduced in C# 2.0. An anonymous method is inline unnamed method in the code. It is created using the delegate keyword and doesn’t required name and return type. Hence we can say, an anonymous method has only body without name, optional parameters and return type. An anonymous method behaves like a regular method and allows us to write inline code in place of explicitly named methods.

Features of anonymous method

  1. A variable, declared outside the anonymous method can be accessed inside the anonymous method.
  2. A variable, declared inside the anonymous method can’t be accessed outside the anonymous method.
  3. We use anonymous method in event handling.
  4. An anonymous method, declared without parenthesis can be assigned to a delegate with any signature.
  5. Unsafe code can’t be accessed within an anonymous method.
  6. An anonymous method can’t access the ref or out parameters of an outer scope.

We discussed that delegates are used to reference any methods that has the same signature as that of the delegate. In other words, you can call a method that can be referenced by a delegate using that delegate object.
Anonymous methods provide a technique to pass a code block as a delegate parameter. Anonymous methods are basically methods without a name, just the body.
You need not specify the return type in an anonymous method; it is inferred from the return statement inside the method body.

Syntax for Writing an Anonymous Method

Anonymous methods are declared with the creation of the delegate instance, with a delegate keyword. For example,
delegate void NumberChanger(int n);
...
NumberChanger nc = delegate(int x)
{
    Console.WriteLine("Anonymous Method: {0}", x);
};
The code block Console.WriteLine("Anonymous Method: {0}", x); is the body of the anonymous method.
The delegate could be called both with anonymous methods as well as named methods in the same way, i.e., by passing the method parameters to the delegate object.
For example,
nc(10);

Example:

The following example demonstrates the concept:
using System;

delegate void NumberChanger(int n);
namespace DelegateAppl
{
    class TestDelegate
    {
        static int num = 10;
        public static void AddNum(int p)
        {
            num += p;
            Console.WriteLine("Named Method: {0}", num);
        }

        public static void MultNum(int q)
        {
            num *= q;
            Console.WriteLine("Named Method: {0}", num);
        }
        public static int getNum()
        {
            return num;
        }

        static void Main(string[] args)
        {
            //create delegate instances using anonymous method
            NumberChanger nc = delegate(int x)
            {
               Console.WriteLine("Anonymous Method: {0}", x);
            };
            
            //calling the delegate using the anonymous method 
            nc(10);

            //instantiating the delegate using the named methods 
            nc =  new NumberChanger(AddNum);
            
            //calling the delegate using the named methods 
            nc(5);

            //instantiating the delegate using another named methods 
            nc =  new NumberChanger(MultNum);
            
            //calling the delegate using the named methods 
            nc(2);
            Console.ReadKey();
        }
    }
}
When the above code is compiled and executed, it produces the following result:
Anonymous Method: 10
Named Method: 15
Named Method: 30

In versions of C# before 2.0, the only way to declare a delegate was to use named methods. C# 2.0 introduced anonymous methods and in C# 3.0 and later, lambda expressions supersede anonymous methods as the preferred way to write inline code. However, the information about anonymous methods in this topic also applies to lambda expressions. There is one case in which an anonymous method provides functionality not found in lambda expressions. Anonymous methods enable you to omit the parameter list. This means that an anonymous method can be converted to delegates with a variety of signatures. This is not possible with lambda expressions. For more information specifically about lambda expressions, see Lambda Expressions (C# Programming Guide).
Creating anonymous methods is essentially a way to pass a code block as a delegate parameter. Here are two examples:
// Create a handler for a click event.
button1.Click += delegate(System.Object o, System.EventArgs e)
                   { System.Windows.Forms.MessageBox.Show("Click!"); };
// Create a delegate. 
delegate void Del(int x);

// Instantiate the delegate using an anonymous method.
Del d = delegate(int k) { /* ... */ };
By using anonymous methods, you reduce the coding overhead in instantiating delegates because you do not have to create a separate method.
For example, specifying a code block instead of a delegate can be useful in a situation when having to create a method might seem an unnecessary overhead. A good example would be when you start a new thread. This class creates a thread and also contains the code that the thread executes without creating an additional method for the delegate.
void StartThread()
{
    System.Threading.Thread t1 = new System.Threading.Thread
      (delegate()
            {
                System.Console.Write("Hello, ");
                System.Console.WriteLine("World!");
            });
    t1.Start();
}
The scope of the parameters of an anonymous method is the anonymous-method-block.
It is an error to have a jump statement, such as gotobreak, or continue, inside the anonymous method block if the target is outside the block. It is also an error to have a jump statement, such as gotobreak, or continue, outside the anonymous method block if the target is inside the block.
The local variables and parameters whose scope contains an anonymous method declaration are called outer variables of the anonymous method. For example, in the following code segment, n is an outer variable:
int n = 0;
Del d = delegate() { System.Console.WriteLine("Copy #:{0}", ++n); };
A reference to the outer variable n is said to be captured when the delegate is created. Unlike local variables, the lifetime of a captured variable extends until the delegates that reference the anonymous methods are eligible for garbage collection.
An anonymous method cannot access the ref or out parameters of an outer scope.
No unsafe code can be accessed within the anonymous-method-block.
Anonymous methods are not allowed on the left side of the is operator.
The following example demonstrates two ways of instantiating a delegate:
  • Associating the delegate with an anonymous method.
  • Associating the delegate with a named method (DoWork).
In each case, a message is displayed when the delegate is invoked.

// Declare a delegate. 
delegate void Printer(string s);

class TestClass
{
    static void Main()
    {
        // Instantiate the delegate type using an anonymous method.
        Printer p = delegate(string j)
        {
            System.Console.WriteLine(j);
        };

        // Results from the anonymous delegate call.
        p("The delegate using the anonymous method is called.");

        // The delegate instantiation using a named method "DoWork".
        p = new Printer(TestClass.DoWork);

        // Results from the old style delegate call.
        p("The delegate using the named method is called.");
    }

    // The method associated with the named delegate. 
    static void DoWork(string k)
    {
        System.Console.WriteLine(k);
    }
}
/* Output:
    The delegate using the anonymous method is called.
    The delegate using the named method is called.
*/
Lambda expression
A lambda expression is an anonymous function that you can use to create delegates or expression tree types. By using lambda expressions, you can write local functions that can be passed as arguments or returned as the value of function calls. Lambda expressions are particularly helpful for writing LINQ query expressions.
To create a lambda expression, you specify input parameters (if any) on the left side of the lambda operator =>, and you put the expression or statement block on the other side. For example, the lambda expression x => x * x specifies a parameter that’s named x and returns the value of x squared. You can assign this expression to a delegate type, as the following example shows:
delegate int del(int i);
static void Main(string[] args)
{
    del myDelegate = x => x * x;
    int j = myDelegate(5); //j = 25
}
To create an expression tree type:
using System.Linq.Expressions;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Expression<del> myET = x => x * x;
        }
    }
}
The => operator has the same precedence as assignment (=) and is right associative (see “Associativity” section of the Operators article).
Lambdas are used in method-based LINQ queries as arguments to standard query operator methods such as Where.
When you use method-based syntax to call the Where method in the Enumerable class (as you do in LINQ to Objects and LINQ to XML) the parameter is a delegate typeSystem.Func<T, TResult>. A lambda expression is the most convenient way to create that delegate. When you call the same method in, for example, the System.Linq.Queryableclass (as you do in LINQ to SQL) then the parameter type is an System.Linq.Expressions.Expression<Func> where Func is any of the Func delegates with up to sixteen input parameters. Again, a lambda expression is just a very concise way to construct that expression tree. The lambdas allow the Where calls to look similar although in fact the type of object created from the lambda is different.
In the previous example, notice that the delegate signature has one implicitly-typed input parameter of type int, and returns an int. The lambda expression can be converted to a delegate of that type because it also has one input parameter (x) and a return value that the compiler can implicitly convert to type int. (Type inference is discussed in more detail in the following sections.) When the delegate is invoked by using an input parameter of 5, it returns a result of 25.
Lambdas are not allowed on the left side of the is or as operator.
All restrictions that apply to anonymous methods also apply to lambda expressions. For more information, see Anonymous Methods (C# Programming Guide).
A lambda expression with an expression on the right side of the => operator is called an expression lambda. Expression lambdas are used extensively in the construction ofExpression Trees (C# and Visual Basic). An expression lambda returns the result of the expression and takes the following basic form:
(input parameters) => expression
The parentheses are optional only if the lambda has one input parameter; otherwise they are required. Two or more input parameters are separated by commas enclosed in parentheses:
(x, y) => x == y
Sometimes it is difficult or impossible for the compiler to infer the input types. When this occurs, you can specify the types explicitly as shown in the following example:
(int x, string s) => s.Length > x
Specify zero input parameters with empty parentheses:
() => SomeMethod()
Note in the previous example that the body of an expression lambda can consist of a method call. However, if you are creating expression trees that are evaluated outside of the .NET Framework, such as in SQL Server, you should not use method calls in lambda expressions. The methods will have no meaning outside the context of the .NET common language runtime.
A statement lambda resembles an expression lambda except that the statement(s) is enclosed in braces:
(input parameters) => {statement;}
The body of a statement lambda can consist of any number of statements; however, in practice there are typically no more than two or three.
delegate void TestDelegate(string s);
…
TestDelegate myDel = n => { string s = n + " " + "World"; Console.WriteLine(s); };
myDel("Hello");
Statement lambdas, like anonymous methods, cannot be used to create expression trees.
You can easily create lambda expressions and statements that incorporate asynchronous processing by using the async and await keywords. For example, the following Windows Forms example contains an event handler that calls and awaits an async method, ExampleMethodAsync.
public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private async void button1_Click(object sender, EventArgs e)
    {
        // ExampleMethodAsync returns a Task.
        await ExampleMethodAsync();
        textBox1.Text += "\r\nControl returned to Click event handler.\r\n";
    }

    async Task ExampleMethodAsync()
    {
        // The following line simulates a task-returning asynchronous process.
        await Task.Delay(1000);
    }
}
You can add the same event handler by using an async lambda. To add this handler, add an async modifier before the lambda parameter list, as the following example shows.
public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        button1.Click += async (sender, e) =>
        {
            // ExampleMethodAsync returns a Task.
            await ExampleMethodAsync();
            textBox1.Text += "\r\nControl returned to Click event handler.\r\n";
        };
    }

    async Task ExampleMethodAsync()
    {
        // The following line simulates a task-returning asynchronous process.
        await Task.Delay(1000);
    }
}
For more information about how to create and use async methods, see Asynchronous Programming with Async and Await (C# and Visual Basic).
Many Standard query operators have an input parameter whose type is one of the Func<T, TResult> family of generic delegates. These delegates use type parameters to define the number and types of input parameters, and the return type of the delegate. Func delegates are very useful for encapsulating user-defined expressions that are applied to each element in a set of source data. For example, consider the following delegate type:
public delegate TResult Func<TArg0, TResult>(TArg0 arg0)
The delegate can be instantiated as Func<int,bool> myFunc where int is an input parameter and bool is the return value. The return value is always specified in the last type parameter. Func<int, string, bool> defines a delegate with two input parameters, int and string, and a return type of bool. The following Func delegate, when it is invoked, will return true or false to indicate whether the input parameter is equal to 5:
Func<int, bool> myFunc = x => x == 5;
bool result = myFunc(4); // returns false of course
You can also supply a lambda expression when the argument type is an Expression<Func>, for example in the standard query operators that are defined in System.Linq.Queryable. When you specify an Expression<Func> argument, the lambda will be compiled to an expression tree.
A standard query operator, the Count method, is shown here:
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
int oddNumbers = numbers.Count(n => n % 2 == 1);
The compiler can infer the type of the input parameter, or you can also specify it explicitly. This particular lambda expression counts those integers (n) which when divided by two have a remainder of 1.
The following line of code produces a sequence that contains all elements in the numbers array that are to the left side of the 9 because that's the first number in the sequence that doesn't meet the condition:
var firstNumbersLessThan6 = numbers.TakeWhile(n => n < 6);
This example shows how to specify multiple input parameters by enclosing them in parentheses. The method returns all the elements in the numbers array until a number is encountered whose value is less than its position. Do not confuse the lambda operator (=>) with the greater than or equal operator (>=).
var firstSmallNumbers = numbers.TakeWhile((n, index) => n >= index);
When writing lambdas, you often do not have to specify a type for the input parameters because the compiler can infer the type based on the lambda body, the parameter’s delegate type, and other factors as described in the C# Language Specification. For most of the standard query operators, the first input is the type of the elements in the source sequence. So if you are querying an IEnumerable<Customer>, then the input variable is inferred to be a Customer object, which means you have access to its methods and properties:
customers.Where(c => c.City == "London");
The general rules for lambdas are as follows:
  • The lambda must contain the same number of parameters as the delegate type.
  • Each input parameter in the lambda must be implicitly convertible to its corresponding delegate parameter.
  • The return value of the lambda (if any) must be implicitly convertible to the delegate's return type.
Note that lambda expressions in themselves do not have a type because the common type system has no intrinsic concept of "lambda expression." However, it is sometimes convenient to speak informally of the "type" of a lambda expression. In these cases the type refers to the delegate type or Expression type to which the lambda expression is converted.
Lambdas can refer to outer variables (see Anonymous Methods (C# Programming Guide)) that are in scope in the method that defines the lambda function, or in scope in the type that contains the lambda expression. Variables that are captured in this manner are stored for use in the lambda expression even if the variables would otherwise go out of scope and be garbage collected. An outer variable must be definitely assigned before it can be consumed in a lambda expression. The following example demonstrates these rules:
delegate bool D();
delegate bool D2(int i);

class Test
{
    D del;
    D2 del2;
    public void TestMethod(int input)
    {
        int j = 0;
        // Initialize the delegates with lambda expressions.
        // Note access to 2 outer variables.
        // del will be invoked within this method.
        del = () => { j = 10;  return j > input; };

        // del2 will be invoked after TestMethod goes out of scope.
        del2 = (x) => {return x == j; };
      
        // Demonstrate value of j:
        // Output: j = 0 
        // The delegate has not been invoked yet.
        Console.WriteLine("j = {0}", j);        // Invoke the delegate.
        bool boolResult = del();

        // Output: j = 10 b = True
        Console.WriteLine("j = {0}. b = {1}", j, boolResult);
    }

    static void Main()
    {
        Test test = new Test();
        test.TestMethod(5);

        // Prove that del2 still has a copy of
        // local variable j from TestMethod.
        bool result = test.del2(10);

        // Output: True
        Console.WriteLine(result);
           
        Console.ReadKey();
    }
}
The following rules apply to variable scope in lambda expressions:
  • A variable that is captured will not be garbage-collected until the delegate that references it becomes eligible for garbage collection.
  • Variables introduced within a lambda expression are not visible in the outer method.
  • A lambda expression cannot directly capture a ref or out parameter from an enclosing method.
  • A return statement in a lambda expression does not cause the enclosing method to return.
  • A lambda expression cannot contain a goto statement, break statement, or continue statement that is inside the lambda function if the jump statement’s target is outside the block. It is also an error to have a jump statement outside the lambda function block if the target is inside the block.

No comments:

Post a Comment