Delegates, Anonymous Methods and Lambdas in C# – The Basics

I’ve been working back through an excellent book – CLR Via C# to try and get to grips with some of the fundamental features of the CLR.  

Coming to Delegates I was aware that this is something that has changed over time.  The 2.0 Framework built on Delegates ant introduced Anonymous Methods.  The 3.5 Framework built on Anonymous Methods and introduced Lambdas.    In it’s simplest form, a Delegate, is a simple way of passing a method as a parameter to another method.   

The basics :

namespace Examples.DelegateEvolution
{
    public static class DelegateTest
    {
        internal delegate int DoMaths(int a, int b);

Define the signature the method to be passed as a parameter must take .   This example method takes two ints as parameters and returns an int.  It’s given the notional name DoMaths.  You can call it anything you like – DoMathsWithTwo, DoSomeMaths…..

        internal static int AddNumbers(int a, int b)
        {
            return a + b;
        }

AddNumbers is a method which takes two ints and returns the sum of them, as an int.  Notice that it has the same signature as DoMaths which was a delegate definition given above. 


        internal static int DoSomeCalc(DoMaths mathsMethod, params int[] paramList)
        {
            int result = 0;
            foreach (int i in paramList)
                result = mathsMethod(result, i);
            return result;
        }

This method takes a method as a parameter and a variable length array of ints, returning an int.   Notice that the method parameter is defined as a type of DoMaths.  That means any parameter passed to DoCalc must conform to the DoMaths definition given above.    Assigned the name mathsMethod, notice that the 5th line takes two ints and returns an int, matching the definition of DoMaths.

Initialising a local variable, result, the method loops through the ints in the array and calls the method passed as a parameter (mathsMethod) passing in two intes (the value of result and the current int from the array).  The value returned from the method is assigned to result.   Once all items in the array has been processed DoCalc returns result to the calling process.


        public static void TestAddDelegateMethod()
        {
            int val = DoSomeCalc(new DoMaths(AddNumbers), 1, 2, 3);
            WriteResult(val);
        }

Here’s the interesting bit, int val is being assigned the result of DoCalc.   DoCalc is being passed the method AddNumbers as a parameter AddNumbers matches the definition of the DoMaths delegate), followed by a variable number of int params (1, 2, 3).  In early frameworks you had to “new up” the method using the delegate method definition – new DoMaths(methodName)

        private static void WriteResult(int result)
        {
            Console.WriteLine(string.Format("Result value is {0}", result));          
        }
    }
}

Simple helper method.

 

As delegates evolved, the need to new up was removed, you no longer had to tell the compiler the method you were passing matched the delegate definition, it could work it out itself.

   int val = DoSomeCalc(new DoMaths(AddNumbers), 1, 2, 3);
         

became shortened to.

   int val = DoSomeCalc(AddNumbers, 1, 2, 3);
 
 

With 2.0 of the framework came Anonymous Methods.   Previously you had to define the method you were going to pass as a parameter.   AddNumbers in the example above.  With 2.0 you could do the following instead :

        public static void TestAddAnonymousType()
        {
            int val = DoSomeCalc(delegate(int a, int b) { return a + b; }, 1, 2, 3);
            WriteResult(val);
        }

No need to create a method just to be able to pass it as a parameter, put the code direct in the method call itself!    There are some obvious advantages to this, if the code is fairly short and easy to read for example.   I think there’s a balance to be struck.  Having the method(s) your passing as delegates defined in your code may provide clarity for someone else picking up your code (or when you come back to it).

 

And then onto 3.5 and Lambdas.  Lambdas are Anonymous functions providing a new, shorter syntax.

 public static void TestAddLambda()
 {
     int val = DoSomeCalc((a, b) => a + b , 1, 2, 3);
     WriteResult(val);
 }

The word delegate is dropped, DoMaths knows it needs a delegate.  The ints are dropped too.  The delegate definition at the top indicates the types passed as a parameter so it’s simply a case of passing the parameter values inside the brackets (a, b).  Everything after => is the body of the lambda.  If the delegate has a return type then it can be inferred from the code and there’s no need to make a return either.

      public static void TestAddLambdaTwo()
      {
         int val = DoSomeCalc((a, b) => AddNumbers(a, b), 1, 2, 3);
         WriteResult(val);
      }  

Provides the same result. The parameters are a and b, and the body of the lambda is call AddNumbers passing a and b.

This post just covers the basics, there’s a lot more to these, especially Lambdas.

Advertisements

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s