This article is also available as a TechRepublic download, which comes complete with a sample Visual Studio project of sample code.

In C# 1.1, declaring and using a delegate required you to have the delegate, a method with a matching signature to execute when the delegate is triggered, and an assignment statement that associated the delegate with the named method. As a new feature of C# 2.0, anonymous methods are able to provide basically the same functionality as the previous named method technique, but do not require a method to be explicitly created before it is associated to the delegate.

You can think of anonymous methods as a short-hand way to implement functionality to be associated with a delegate. If you examine the resulting IL from both an anonymous method implementation and a named method implementation, you will see that there is very little differenence between the two. When the compiler sees an anonymous method, it creates a named method within the class and associates that with the delegate. So anonymous methods perform very similar at runtime to named methods -- the performance increase is in developer productivity, not runtime execution.

How to use anonymous methods

Anonymous methods are easier to explain and understand with less talk and more code. The following examples should demonstrate how you can take advantage of anonymous methods yourself.

Example #1 - The basics

Using an anonymous method is simple. You just place the anonymous method in the association statement where you would normally put a named method. In this example, I am associating the anonymous method with an Example 1 delegate:

Example listing 1

    #region Simple example - Example1
    privatedelegatevoidExample1();

    privatevoid btnExample1_Click(object sender, EventArgs e)
    {
        //Declare an instance of the Example1 delegate.
        // You can see where I'm using the anonymous
        // method in place of a named method - it follows
        // the delegate() keyword.
        Example1 example =
            newExample1(
                delegate()
                {
                    MessageBox.Show("Example1");
                });

        example();
    }
    #endregion

Example #2 – Variable scope

The scope of any variable declared within the anonymous method is the anonymous method code block. However, anonymous methods do have the ability to access variables outside their code block, as long as the variables are in scope where the anonymous method is used. These variables are refered to by Microsoft as outer variables. The following Example 2 shows an anonymous method referencing outer variables:

Example listing 2

   #region Variable scope example - Example2
   privatedelegatevoidExample2();

   privatevoid btnExample2_Click(object sender, EventArgs e)
   {
       //Setup our parameters.
       string firstName = "Zach";
       string lastName = "Smith";

       //Create an instance of the Example2 delegate with an
       // anonymous method.
       Example2 example =
           newExample2(
               delegate() {
                   MessageBox.Show(firstName + " " + lastName);
              });

       //Execute the delegate.
       example();
   }
   #endregion

Note that, according to MSDN, ref and out parameters cannot be accessed within an anonymous method.

Example #3 – Passing parameters

You can pass parameters to anonymous methods just the same as you can to delegates that reference named parameters. The following Example 3 demonstrates this type of functionality:

Example listing 3

   #region Parameter example - Example3
   privatedelegatevoidExample3(string firstName, string lastName);

   privatevoid btnExample3_Click(object sender, EventArgs e)
   {
       //Setup our parameters.
       string parameter1 = "Zach";
       string parameter2 = "Smith";

       //Create an instance of the Example3 delegate with an
       // anonymous method.
       Example3 example =
           newExample3(
               delegate(string firstName, string lastName)
               {
                   MessageBox.Show("Example3: " + firstName + " " + lastName);
               });

       //Execute the delegate.
       example(parameter1, parameter2);
   }
   #endregion

Example #4 – Multiple method association

As with named methods, it is possible to associate multiple anonymous methods with the same delegate. It is also possible to associate a named method and an anonymous method to a single delegate. This could be useful in several situations -- one that comes to mind is adding a simple handler to a button's click event. The following code (Example 4) shows a delegate with both an anonymous method and a named method associated with it:

Example listing 4

   #region Multiple method association (stacking) - Example4
   privatedelegatevoidExample4(string firstName, string lastName);

   privatevoid btnExample4_Click(object sender, EventArgs e)
   {
       //Setup our parameters.
       string parameter1 = "Zach";
       string parameter2 = "Smith";

       //Create an instance of the Example4 delegate with an
       // anonymous method.
       Example4 example =
           newExample4(
               delegate(string firstName, string lastName)
               {
                   MessageBox.Show("Example4: " + firstName + " " + lastName);
               });

       //Add another method to the delegate - this time
       // a named method.
       example += newExample4(Example4NamedMethod);

       //Execute the delegate.
       example(parameter1, parameter2);
   }

   privatevoid Example4NamedMethod(string firstName, string lastName)
   {
       MessageBox.Show("Example4Method: " + firstName + " " + lastName);
   }
   #endregion

Example #5 – Passing anonymous methods as parameters

As with named methods, it is possible to pass an anonymous method as a parameter to a function. This isn't a feature that I would expect to see used on a regular basis, however I'm sure the need will arise. The following code (Example 5) demonstrates this type of functionality, along with passing a named method as a parameter to a function:

Example listing 5

   #region Passing anonymous methods - Example5
   privatedelegatevoidExample5(string firstName, string lastName);

   privatevoid btnExample5_Click(object sender, EventArgs e)
   {
       //Execute Passit and pass the anonymous method.
       Passit((Example5)delegate(string firstName, string lastName)
               {
                   MessageBox.Show("Example5: " + firstName + " " + lastName);
               });

       //Execute Passit with the named method.
       Passit(Example5NamedMethod);
   }

   privatevoid Example5NamedMethod(string firstName, string lastName)
   {
       MessageBox.Show("Example5Method: " + firstName + " " + lastName);
   }

   privatevoid Passit(Example5 example)
   {
       example("Zach", "Smith");
   }
   #endregion

Example #6 – Accessing class members

This is an extension of the variable scope example shown above (Example 2). However, this example (Example 6) demonstrates that anonymous methods are also able to execute named methods outside of their code block, as long as the named method is in scope for the anonymous method:

Example listing 6

    #region Accessing class members - Example6
    privatedelegatevoidExample6();

    privateint _customerId;
    privatestring _customerCode;

    publicint CustomerID
    {
        get { return _customerId; }
        set { _customerId = value; }
    }

    publicstring CustomerCode
    {
        get { return _customerCode; }
        set { _customerCode = value; }
    }

    privatevoid btnExample6_Click(object sender, EventArgs e)
    {
        //Populate out properties.
        this.CustomerID = 90;
        this.CustomerCode = "1337HK";

        //Setup the delegate/anonymous method.
        Example6 example =
            newExample6(
                delegate
                {
                    this.ShowCustomer(this.CustomerID, this.CustomerCode);
                });

        //Execute the delegate.
        example();

        //Change the properties.
        this.CustomerID = 54;
        this.CustomerCode = "L4M3";

        //Execute the delegate again.
        // Notice that the new values are reflected.
        example();
    }

    privatevoid ShowCustomer(int customerId, string customerCode)
    {
        MessageBox.Show(
            String.Format("CustomerID: {0}\nCustomer Code: {1}",
                            customerId, customerCode));
    }
    #endregion

Note that I'm making two calls to the delegate associated with the anonymous method. You may find it interesting that in those calls, the method will output two different sets of values. This is due to the fact that outer variables used in an anonymous method are referenced at the time of the anonymous method's creation. This means that any changes to those variables will be reflected when the anonymous method accesses the variables.

You might also notice that the delegate keyword doesn't have parenthesis after it in this instance. When an anonymous method doesn't require parameters, the parenthesis are optional.

Comments

I hope this article has helped you understand how anonymous methods can be used. While they are certainly not revolutionary, they are an important step in the evolution of C# as a programmer-friendly language. I would like to know your thoughts and ideas on how anonymous methods affect programming in C#. Please leave a comment or e-mail me and let me know what you think!