AddThis Social Bookmark Button

Print

New Language Features in C# 2.0, Part 1

by Matthew MacDonald, coauthor of ASP.NET In a Nutshell, 2nd edition
04/05/2004

Four years ago, a new upstart language named C# surprised the development world with its elegance and consistency. Now that Microsoft has released a technology preview version of Visual Studio 2005 (formerly codenamed Whidbey), .NET's favorite language is back with some new innovations. In this two-part series, you'll get a first look at three of the four major language refinements in the latest version of C#.

Anonymous Methods

In .NET programming, every executable line of code takes place inside of a method, and every method is explicitly declared at the class level -- until now. In C# 2.0, you can declare a method inside of another piece of code, where a delegate is expected. This embedded method is called an anonymous method. (Anonymous methods will look familiar to you if you've used lambda functions in the Lisp programming language.)

Anonymous methods are primarily useful if you want to quickly hook up an event handler. For example, here's the standard way to hook up an event handler that responds to the click of a button (in any version of .NET):

public partial class Form1 : Form
{
  // This method connects the event handler.
  public Form1()
  {
    InitializeComponent();
    button1.Click += new EventHandler(ButtonClick);
  }

  // This is the event handling method.
  private void ButtonClick(object sender, EventArgs e)
  {
    MessageBox.Show("You clicked the button.");
  }
}

In this example, there are two methods. Form1() initializes the window and connects the event handlers. ButtonClick() receives the event when the user clicks the button.

Here's how you could rewrite this example using an anonymous method:

public partial class Form1 : Form
{
  public Form1()
  {
    InitializeComponent();

    button1.Click += delegate(object sender, EventArgs e)
    {
      // The following code is part of an anonymous method.
      MessageBox.Show("You clicked the button, and " +
        "This is an anonymous method!");
    };
  }
}

Notice that the event handler method is defined inside of Form1(), and is attached directly to the Click event. The anonymous method starts with the keyword delegate, followed by the parameter list and then the actual method code. Essentially, the Form1() method defines a new method, but doesn't execute it. (In this example, the code in the anonymous method won't run until the Click event fires.)

When you declare an anonymous method, the C# compiler has some liberty to decide how it handles the situation. In this example, the compiler creates a new, uniquely named method in the Form1 class. This anonymous method has access to all the public and private member variables and properties of the Form1 class.

Programming C#

Related Reading

Programming C#
By Jesse Liberty

Even more interestingly, the anonymous method also has access to local variables defined in the procedure where the anonymous method is declared. Here's an example that shows this somewhat counterintuitive ability:

public partial class Form1 : Form
{
  public Form1()
  {
    InitializeComponent();

    string tempVar = "TEST";
    button1.Click += delegate(object sender, EventArgs e)
    {
      MessageBox.Show("tempVar contains " + tempVar);
    };
  }
}

To make this work, the C# compiler handles this code a little differently. It actually creates a new class that it nests inside of the Form1 class. It adds the anonymous method to the new class, along with a private member variable to store the contents from tempVar.

You don't need to attach an anonymous method to an event. You can also declare an anonymous method and assign it to a delegate variable. This technique is useful if you need to pass a delegate as a callback, or if you want to attach the same anonymous method to two event handlers, as shown here:

public partial class Form1 : Form
{
  public Form1()
  {
    InitializeComponent();

    // Declare the delegate that points to an anonymous method.
    EventHandler clickHandler = 
      delegate(object sender, EventArgs e)
      {
        MessageBox.Show("You clicked the button, and " +
          "This is an anonymous method!");
      };

    // Attach the delegate to two events.
    button1.Click += clickHandler;
    button2.Click += clickHandler;
  }
}

Overall, anonymous methods make most sense if your method code is relatively short; otherwise, it can be difficult to distinguish the embedded anonymous method code from the surrounding method code. One reason you might want to use anonymous methods is to simplify the handling of asynchronous events. Using an anonymous method, you can define how you want to handle the completion of an asynchronous task in the same context where you start the asynchronous task. This approach can clarify your code.

Iterators

Often, developers need to create classes that support enumeration. When a class supports enumeration, you can use the convenient foreach syntax to step through a group of items. For example, if you create an OrderCatalog class that contains a group of OrderItem instances, you might want to enumerate over all of the items using this code:

foreach (item OrderItem in catalog)
{
  // (Process OrderItem here.)
}

This code gets translated by the C# compiler to use the GetEnumerator() method of the class. Technically, it looks like this:

Enumerator e = catalog.GetEnumerator();
while (e.MoveNext())
{
  OrderItem item = e.Current;
  // (Process OrderItem here.)
}

As a result, this pattern only works with classes that implement the IEnumerable interface. Creating a class that supports enumeration in C# 1.0 ranges from mildly inconvenient to annoyingly awkward. In C# 2.0, a new language feature known as iterators makes it much easer to create classes that support enumeration. Instead of building a state machine to keep track of your position in a collection, you create one public method named GetEnumerator() that returns all of the values directly using the new yield return keyword.

For example, here's a simple class that yields three pieces of information:

public class DecoratingColors
{
  public string WallPaint;
  public string Carpet;
  public string Furniture;
  public IEnumerator<string> GetEnumerator()
  {
      yield return WallPaint;
      yield return Carpet;
      yield return Furniture;
  }
}

When you use foreach on a DecoratingColors instance, you'll wind up with three strings, one after the other.

To see the real rewards of iterators, you need to consider a more realistic example. The following code shows the OrderCatalog class, which contains a private collection of OrderItem instances. In this example, the GetEnumerator() method traverses all the items in the private collection in a loop, returning one item each time.

public class OrderCatalog
{
  private ArrayList orderItems = new ArrayList(); 

	public void Load()
  {
    // Fill collection for a test.
    orderItems.Clear();
    orderItems.Add(new OrderItem("Item 1"));
    orderItems.Add(new OrderItem("Item 2"));
    orderItems.Add(new OrderItem("Item 3"));
  } 

	public IEnumerator<OrderItem> GetEnumerator()
  {
    foreach (OrderItem item in orderItems)
    {
      yield return item;
    }
  }
}

public class OrderItem
{
  private string name;
  
  public string Name
  {
    get { return name; }
  } 

  public OrderItem(string name)
  {
    this.name = name;
  }
}

Here's the code that puts this example to the test:

OrderCatalog catalog = new OrderCatalog();
catalog.Load();
foreach (OrderItem item in catalog)
{
  MessageBox.Show(item.Name);
}

The beauty of iterators is that the enumerable class can concentrate on providing information, while the consumer can concentrate on retrieving it. Neither part needs to worry about the actual implementation details of how positioned is maintained.

Partial Classes

Partial classes give you the ability to split a single class into more than one source code (.cs) file. Here's what a partial class looks like when it's split over two files:

// Stored in file MyClass1.cs
public partial class MyClass
{
  public MethodA()
  {...}
}

// Stored in file MyClass2.cs
public partial class MyClass
{
  public MethodB()
  {...}
}

When you build the application, Visual Studio .NET tracks down each piece of MyClass and assembles it into a complete, compiled class with two methods, MethodA() and MethodB().

Partial classes don't offer much in the way of solving programming problems, but they can be useful if you have extremely large, unwieldy classes. (Of course, this might be a sign that you haven't properly factored your problem, in which case you should really break your class down into separate classes.) The real purpose of partial classes in .NET is to hide automatically generated designer code.

For example, if you build a .NET form in Visual Studio 2005, your event- handling code is placed in the source code file for the form, but the designer code that creates and configures each control and connects the event handlers is nowhere to be seen. In order to see this code, you need to select Project-->Show All Files from the Visual Studio menu. When you do, a new file appears with the other half of the class. For example, if you create a new form named Form1, you'll actually wind up with a Form1.cs file for your code and a Form1.Designer.cs file that contains the automatically generated part.

Summary

In the next article in this series, you'll learn about the sexiest new language feature in C# (and no, it isn't multiple inheritance). In the meantime, for a more detailed look at the C# language rules, surf to the C# language page at MSDN, at msdn.microsoft.com/vcsharp/team/language. You'll find a link that allows you to download a detailed white paper on the new C# language specifications, along with useful insight from the C# language designers in the "Ask a Language Designer" section of the site.

Matthew MacDonald is a developer, author, and educator in all things Visual Basic and .NET. He's worked with Visual Basic and ASP since their initial versions, and written over a dozen books on the subject, including The Book of VB .NET (No Starch Press) and Visual Basic 2005: A Developer's Notebook (O'Reilly). His web site is http://www.prosetech.com/.


Return to ONDotnet.com