Anonymous Methods

At various times, the code contained within the body of a delegate will be quite small and used in only one place. Many developers prefer to forward all event handlers to another method so that other event handlers can reuse the same code logic. In situations such as these, creating a method just so the call can be forwarded to another method isn’t exactly elegant, and it’s pref­erable to have the ability to include the code that forwards the call to the end recipient inline with the delegate creation. C# 2.0 provides this functionality through a new feature called anonymous methods.

Anonymous methods offload the tedious work of declaring a separate method to the compiler. Consider the following code, which is fairly verbose:

class Program {

static void Main(string[] args)

{

AppDomain.CurrentDomain.CatchingException +=

new CatchingExceptionEventHandler(CurrentDomain_CatchingException);

}

static void CurrentDomain_CatchingException(object sender,

CatchingExceptionEventArgs e)

{

Console.WriteLine(“An exception is being caught in the app domain”);

}

}

Using anonymous methods, you can convert this code to the following:

class Program {

static void Main(string[] args)

{

AppDomain.CurrentDomain.CatchingException += delegate(object sender, CatchingExceptionEventArgs e)

{

Console.WriteLine(“An exception is being caught in the app domain”); };

}

}

}

If the code inside the anonymous method doesn’t need to access the values of the dele­gate’s parameters, you can exclude these to further simplify the code:

class Program {

static void Main(string[] args)

{

AppDomain.CurrentDomain.CatchingException += delegate {

Console.WriteLine(“An exception is being caught in the app domain”);

};

}

}

In the anonymous method snippets, the event hookup and delegate declaration take place in the same line. Although this isn’t a profound language improvement, it can be quite conve­nient and gives the code a more natural flow when the delegate body is short.

Anonymous methods are extracted by the compiler and placed inside a generated method with parameters appropriate to the delegate. An additional benefit of anonymous methods is that the generated method won’t appear in Visual Studio’s IntelliSense feature, and the method name contains characters that aren’t legal to use in C# (although it’s legal from the CLR’s perspective), so it can’t be called directly in C#. You shouldn’t rely upon the inability to call the method in C# as a security measure, and it’s still possible to call the method using reflection (more about this in Chapter 38) or using a different language.

Anonymous methods don’t expose the full power of delegates. Because no delegate instance is explicitly created in the code, it isn’t possible to unsubscribe to event handlers, because this requires a reference to the delegate instance for which the subscription should be removed. In most circumstances, this isn’t overly limiting, because the lifetime of the raiser and listener will be identical, but if the object raising the events is long-lived, the inability to unsubscribe will result in the event raiser’s reference preventing the collection of event listeners that are no longer referenced by any other object.

If a delegate defines ref or out parameters, anonymous methods can’t be used in place of the delegate, as anonymous methods don’t support the ability to deal with these parameters.

One of the more interesting features of anonymous method is the ability to access the local variables of the method that declares the anonymous method. To achieve the same outcome without anonymous methods, the local variables need to be elevated to class member variables so they can be accessed by the delegate instantiator and the delegate method. This is similar to what the compiler does when the delegate instantiator’s local variables (which are termed outer variables) are accessed inside the anonymous method. Consider the following example, where the generic ForEach method of Array calculates the sum on each element in an array:

int sum = 0;

int[] arr = new int[] { 1, 2, 3 };

Array.ForEach(arr, delegate(int i) { sum += i; });

Console.WriteLine(sum);

In this case, the outer variable is read from and written to in the anonymous method. In this case, the compiler will generate a private nested class with a name containing characters that will prevent C# code from accessing it directly. The compiler will also use the nested class to store the value of the sum outer variable.

Source: Gunnerson Eric, Wienholt Nick (2005), A Programmer’s Introduction to C# 2.0, Apress; 3rd edition.

Leave a Reply

Your email address will not be published. Required fields are marked *