Anonymous Methods Exposed!

Hi there! This is my first ever blog entry. I figured I needed to start a blog while I could still get away with saying that I came fashionably late to the blogging phenomenon. Content wise you can expect a broad spectrum of material to show up here. Given my interests most of it is likely going to be technology related, specifically .NET, but in theory any of my synaptic misfires could find their way here.

For this first post I am going to focus on a new feature coming out in the next version of the C# language called “anonymous methods“. Anonymous methods are an extension to the delegate feature that we as .NET developers know and love.

Just to recap, a delegate is a bit like a function pointer with one crucial difference, type safety. Delegates are defined like methods with a specific set of arguments and a return type, except the implementation is missing. Once you have the delegate defined you can create an instance of it which “points“ to any method which matches the signature of the delegate. Once the delegate is defined you can invoke it like a method. The snippets of code below show how this works today.

// Delegate definition.

public delegate void Greeter(string name);

 

// Method that matches delegate signature.

public void SayGDay(string name)

{

  Console.WriteLine(“G’day {0}!“, name);

}

 

// Code that creates the delegate instance and

// invokes it.

Greeter aussieGreeter = new Greeter(SayGDay);

aussieGreeter(“World!“);

Now that we have that out of the way we can look at anonymous methods. With anonymous methods you don’t have to define a separate method that the delegate points to, you can just inline the code to be executed when you create the delegate instance. That’s why they are called anonymous methods, they don’t have a name!

// Creating the delegate instance declaring an

// anonymous method inline.

Greeter aussieGreeter = delegate

  {

    Console.WriteLine(“G’day {0}!”, name);

  };

aussieGreeter(“World”);

That’s a little more succinct, although I think the jury is still out on whether it makes more readable or maintainable code. I’ll save my judgment for when I have had a chance to use it in anger a little bit more. Now those of you that have been keeping an eye on the C# language enhancements will be noting that the above code wouldn’t actually compile. I’ll address that right now.

When the above code is compiled the C# compiler will report the error CS0103, or in other words “The name ‘name’ does not exist in the current context”. For some reason, I’m not quite sure why, the compiler requires you to specify the arguments that the anonymous method accepts.

// Anonymous method with arguments defined.

Greeter aussieGreeter = delegate(string name)

  {

    Console.WriteLine(“G’day {0}!”, name);

  };

aussieGreeter(“World”);

That’s better! The compiler should now happily compile that code. Now, anonymous methods are simply a compiler trick, the runtime doesn’t know anything about them. When the compiler encounters the above code it strips out the inline method and places into a method and creates code not unlike the code we saw in the first example, the difference being that the compiler as dynamically generated a method name. You can use ILDasm.exe to open up the compiler output and see what that name is (screenshot).

I can imagine this functionality being a real boon writing Windows-based applications where you are essentially handling a whole bunch of events many of which just need to do slight UI tweaks like enabling and disabling things like menu items and buttons. But wait! There’s more!

Using anonymous methods it is actually possible to “capture” object instances that are accessible to the scope of the method containing the inline code. That’s a bit of a mouthful so lets just jump into some code.

// Anonymous method capturing an object instance

// from the containing method.

BabelFish fish = new BabelFish();

Greeter universalGreeter = delegate(string name)

  {

    string greeting = fish.Translate(“Hello”);

    Console.WriteLine(“{0} {1}!”, greeting, name);

  }

universalGreeter(“World”);

Doesn’t that make your hair on the back of your neck stand up! We already know that the compiler is just creating a method for us when it compiles, and that method’s signature conforms to the delegate, so how is the code in the anonymous method getting a reference to the BabelFish instance?

Well, once again the compiler is doing lots of work in the background in order to make this work. If you use ILDasm.exe once again its possible to figure out what is going on behind the scenes (screenshot). Notice that the C# compiler has generated an inner class and moved the dynamically generated method into that class. Closer inspection of the inner class shows that it actually has a field named “fish” that is of type BableFish. That might seem like a lot of extra work but if you think about object lifetime it makes a lot of sense, in fact, its quite clever.

When you create a delegate it establishes a reference between the delegate instance and the object instance that contains the method. By moving the anonymous method off onto its own class along with any object instances that it captures; when the reference to the inner class instance is destroyed it will become eligible for garbage collection, if the captured object instances aren’t referenced anywhere else they will become eligible for collection too.

Well, thats all I have to say about anonymous methods for now. My advice to you is have a bit of a play with them but keep an idea out on how they affect your code readability and overall maintainability. I’m not sure either way, but its going to be interesting finding out!

One thought on “Anonymous Methods Exposed!

Leave a Reply

Fill in your details below or click an icon to log in:

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