C#

Create Elegant Code With Anonymous Methods, Iterators, And Partial Classes

Juval Lowy

This article discusses:

  • Iterating over collections
  • Spanning class definitions across files
  • Anonymous methods for use with delegates
  • Other new C# features in Visual Studio 2005
This article uses the following technologies:
C# and Visual Studio

Code download available at:C20.exe(170 KB)

Contents

Iterators
Iterator Implementation
Recursive Iterations
Partial Types
Anonymous Methods
Passing Parameters to Anonymous Methods
Anonymous Method Implementation
Generic Anonymous Methods
Anonymous Method Examples
Delegate Inference
Property and Index Visibility
Static Classes
Global Namespace Qualifier
Inline Warning
Conclusion

Fans of the C# language will find much to like in Visual C#® 2005. Visual Studio® 2005 brings a wealth of exciting new features to C#, such as generics, iterators, partial classes, and anonymous methods. While generics is the most talked-about feature, especially among C++ developers who are familiar with templates, the other new features are equally important additions to your Microsoft® .NET development arsenal as well. These important features and language additions will improve your overall productivity compared to the first version of C#, leaving you to write cleaner code faster.

Iterators

In C# 1.0, you can iterate over data structures such as arrays and collections using a foreach loop:

string[] cities = {"New York","Paris","London"}; foreach(string city in cities) { Console.WriteLine(city); }

In fact, you can use any custom data collection in the foreach loop, as long as that collection type implements a GetEnumerator method that returns an IEnumerator interface. Usually you do this by implementing the IEnumerable interface:

public interface IEnumerable { IEnumerator GetEnumerator(); } public interface IEnumerator { object Current{get;} bool MoveNext(); void Reset(); }

Often, the class that is used to iterate over a collection by implementing IEnumerable is provided as a nested class of the collection type to be iterated. This iterator type maintains the state of the iteration. A nested class is often better as an enumerator because it has access to all the private members of its containing class. This is, of course, the Iterator design pattern, which shields iterating clients from the actual implementation details of the underlying data structure, enabling the use of the same client-side iteration logic over multiple data structures, as shown in Figure 1.

Figure 1 Iterator Design Pattern

Figure 1** Iterator Design Pattern **

In addition, because each iterator maintains separate iteration state, multiple clients can execute separate concurrent iterations. Data structures such as Array and Queue support iteration out of the box by implementing IEnumerable. The code generated in the foreach loop simply obtains an IEnumerator object by calling the class's GetEnumerator method and uses it in a while loop to iterate over the collection by continually calling its MoveNext method and Current property. You can use IEnumerator directly (without a foreach statement) if you need explicit iteration over the collection.

But there are some problems with this approach. The first is that if the collection contains value types, obtaining the items requires boxing and unboxing them because IEnumerator.Current returns an Object. This results in potential performance degradation and increased pressure on the managed heap. Even if the collection contains reference types, you still incur the penalty of the down-casting from Object. While unfamiliar to most developers, in C# 1.0 you can actually implement the iterator pattern for each loop without implementing IEnumerator or IEnumerable. The compiler will choose to call the strongly typed version, avoiding the casting and boxing. The result is that even in version 1.0 it's possible not to incur the performance penalty.

To better formulate this solution and to make it easier to implement, the Microsoft .NET Framework 2.0 defines the generic, type-safe IEnumerable<T> and IEnumerator<T> interfaces in the System.Collections.Generic namespace:

public interface IEnumerable<T> : IEnumerable { IEnumerator<T> GetEnumerator(); } public interface IEnumerator<T> : IEnumerator,IDisposable { T Current{get;} }

Because the generic interfaces are derived from the non-generic ones, any legacy client that expects the old interfaces can also work with a new collection that supports the new interfaces. The side effect this has on your collection code is that you have to use explicit interface implementation, because you cannot overload methods based on returned type alone.

The code in Figure 2 shows a simple city collection implementing IEnumerable<string>, and Figure 3 shows how the compiler uses that interface when spanning the code of the foreach loop. The implementation in Figure 2 uses a nested class called MyEnumerator, which accepts as a construction parameter a reference back to the collection to be enumerated. MyEnumerator is intimately aware of the implementation details of the city collection, an array in this example. The MyEnumerator class maintains the current iteration state in the m_Current member variable, which is used as an index into the array. Also note in Figure 2 how the non-generic methods IEnumerable.GetEnumerator and IEnumerator.Current delegate their implementation to the generic methods of the new interfaces.

Figure 3 Simple Iterator

CityCollection cities = new CityCollection(); //For this foreach loop: foreach(string city in cities) { Trace.WriteLine(city); } //The compiler generates this equivalent code: IEnumerable<string> enumerable = cities; IEnumerator<string> enumerator = enumerable.GetEnumerator(); using(enumerator) { while(enumerator.MoveNext()) { Trace.WriteLine(enumerator.Current); } }

Figure 2 Implementing IEnumerable<string>

public class CityCollection : IEnumerable<string> { string[] m_Cities = {"New York","Paris","London"}; IEnumerator<string> IEnumerable<string>.GetEnumerator() { return new MyEnumerator(this); } IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<string>)this).GetEnumerator(); } //Nested class definition class MyEnumerator : IEnumerator<string> { CityCollection m_Collection; int m_Current; public MyEnumerator(CityCollection collection) { m_Collection = collection; m_Current = -1; } void IEnumerator.Reset() { m_Current = -1; } bool IEnumerator.MoveNext() { m_Current++; return(m_Current < m_Collection.m_Cities.Length); } string IEnumerator<string>.Current { get { if(m_Current == -1) throw new InvalidOperationException(); return m_Collection.m_Cities[m_Current]; } } object IEnumerator.Current { get { return ((IEnumerator<string>)this).Current; } } public void Dispose() {} } }

The second and more difficult problem is implementing the iterator. Although that implementation is straightforward for simple cases (as shown in Figure 2), it is challenging with more advanced data structures, such as binary trees, which require recursive traversal and maintaining iteration state through the recursion. Moreover, if you require various iteration options, such as head-to-tail and tail-to-head on a linked list, the code for the linked list will be bloated with various iterator implementations. This is exactly the problem that C# 2.0 iterators were designed to address. Using iterators, you can have the C# compiler generate the implementation of IEnumerator or IEnumerator<T> for you. The C# compiler can automatically generate a nested class to maintain the iteration state. You can use iterators on a generic collection or on a type-specific collection. All you need to do is tell the compiler what to yield in each iteration. As with manually providing an iterator, you need to expose a GetEnumerator method, typically by implementing IEnumerable or IEnumerable<T>.

You tell the compiler what to yield using the new C# yield return statement. For example, here is how you use C# iterators in the city collection instead of the manual implementation of Figure 2.

public class CityCollection : IEnumerable<string> { string[] m_Cities = {"New York","Paris","London"}; IEnumerator<string> IEnumerable<string>.GetEnumerator() { for(int i = 0; i<m_Cities.Length; i++) yield return m_Cities[i]; } IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<string>)this)GetEnumerator(); } }

You can also use C# iterators on non-generic collections:

public class CityCollection : IEnumerable { string[] m_Cities = {"New York","Paris","London"}; public IEnumerator GetEnumerator() { for(int i = 0; i<m_Cities.Length; i++) yield return m_Cities[i]; } }

In addition, you can use C# iterators on fully generic collections, as shown in Figure 4. When using a generic collection and iterators, the specific type used for IEnumerable<T> in the foreach loop is known to the compiler from the type used when declaring the collection—a string in this case:

LinkedList<int,string> list = new LinkedList<int,string>(); // Some initialization of list, then foreach(string item in list) { Trace.WriteLine(item); }

This is similar to any other derivation from a generic interface.

Figure 4 Providing Iterators on a Generic Linked List

//K is the key, T is the data item class Node<K,T> { public K Key; public T Item; public Node<K,T> NextNode; } public class LinkedList<K,T> : IEnumerable<T> { Node<K,T> m_Head; IEnumerator<T> IEnumerable<T>.GetEnumerator() { Node<K,T> current = m_Head; while(current != null) { yield return current.Item; current = current.NextNode; } } IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<T>)this).GetEnumerator(); } // More methods and members }

If for some reason you want to stop the iteration midstream, use the yield break statement. For example, the following iterator will only yield the values 1, 2, and 3:

public IEnumerator<int> GetEnumerator() { for(int i = 1; i <5; i++) { yield return i; if(i > 2) yield break; } }

Your collection can easily expose multiple iterators, each used to traverse the collection differently. For example, to traverse the CityCollection class in reverse order, provide a property of type IEnumerable<string> called Reverse:

public class CityCollection { string[] m_Cities = {"New York","Paris","London"}; public IEnumerable<string> Reverse { get { for(int i=m_Cities.Length-1; i>= 0; i--) yield return m_Cities[i]; } } }

Then use the Reverse property in a foreach loop:

CityCollection collection = new CityCollection(); foreach(string city in collection.Reverse) { Trace.WriteLine(city); }

There are some limitations to where and how you can use the yield return statement. A method or a property that has a yield return statement cannot also contain a return statement because that would improperly break the iteration. You cannot use yield return in an anonymous method, nor can you place a yield return statement inside a try statement with a catch block (and also not inside a catch or a finally block).

Iterator Implementation

The compiler-generated nested class maintains the iteration state. When the iterator is first called in a foreach loop (or in direct iteration code), the compiler-generated code for GetEnumerator creates a new iterator object (an instance of the nested class) with a reset state. Every time the foreach loops and calls the iterator's MoveNext method, it begins execution where the previous yield return statement left off. As long as the foreach loop executes, the iterator maintains its state. However, the iterator object (and its state) does not persist across foreach loops. Consequently, it is safe to call foreach again because you will get a new iterator object to start the new iteration.

But how is the nested iterator class implemented and how does it manage its state? The compiler transforms a standard method into a method that is designed to be called multiple times and that uses a simple state machine to resume execution after the previous yield statement. The compiler is even smart enough to concatenate multiple yield return statements in the order they appear:

public class CityCollection : IEnumerable<string> { IEnumerator<string> IEnumerable<string>.GetEnumerator() { yield return "New York"; yield return "Paris"; yield return "London"; } IEnumerator IEnumerable.GetEnumerator() {...} }

Let's take a look at the IEnumerable<string>.GetEnumerator method of the class shown in the following lines of code:

public class MyCollection : IEnumerable<string> { IEnumerator<string> IEnumerable<string>.GetEnumerator() { //Some iteration code that uses yield return } IEnumerator IEnumerable.GetEnumerator() {...} }

When the compiler encounters a class member with a yield return statement such as this, it injects the definition of a nested class called GetEnumeratorrandom unique string of characters and numbers, as shown in the C# pseudocode in Figure 5. (You should remember that the names of the compiler-generated classes and fields—are subject to change in future releases. You should not attempt to use reflection to get at those implementation details and expect consistent results.)

Figure 5 The Compiler-Generated Iterator

public class MyCollection : IEnumerable<string> { IEnumerator<string> IEnumerable<string>.GetEnumerator() { GetEnumerator>d__0 impl = new GetEnumerator>d__0(); impl.<>0_this = this; return impl; } private sealed class GetEnumerator>d__0 : IEnumerator<string> { public MyCollection <>0__<this>; // Back reference to the collection string <>1__current; // state machine members go here string IEnumerator<string>.Current { get { return <>1__current; } } object IEnumerator.Current { get { return <>1__current; } } bool IEnumerator.MoveNext() { //State machine management } IDisposable.Dispose() { //State machine cleanup } } }

The nested class implements the same IEnumerable or IEnumerable<T> interface returned from the class member. The compiler replaces the code in the class member with an instantiation of the nested type, assigning to the nested class a reference back to the collection, similar to the manual implementation shown in Figure 2. The nested class is actually the one providing the implementation of IEnumerator or IEnumerator<T>.

Recursive Iterations

Iterators really shine when it comes to iterating recursively over a data structure such as a binary tree or any complex graph of interconnecting nodes. With recursive iteration, it is very difficult to manually implement an iterator, yet using C# iterators it is done with great ease. Consider the binary tree in Figure 6. The full implementation of the tree is part of the source code available with this article.

Figure 6 Implementing a Recursive Iterator

class Node<T> { public Node<T> LeftNode, RightNode; public T Item; } public class BinaryTree<T> { Node<T> m_Root; public void Add(params T[] items) { Array.ForEach(items, Add); } public void Add(T item) {...} public IEnumerable<T> InOrder { get { return ScanInOrder(m_Root); } } IEnumerable<T> ScanInOrder(Node<T> root) { if(root.LeftNode != null) { foreach(T item in ScanInOrder(root.LeftNode)) { yield return item; } } yield return root.Item; if(root.RightNode != null) { foreach(T item in ScanInOrder(root.RightNode)) { yield return item; } } } }

The binary tree stores items in nodes. Each node holds a value of the generic type T, called Item. Each node has a reference to a node on the left and a reference to a node on the right. Values smaller than Item are stored in the left-side subtree, and larger values are stored in the right-side subtree. The tree also provides an Add method for adding an open-ended array of values of the type T, using the params qualifier:

public void Add(params T[] items);

The tree provides a public property called InOrder of type IEnumerable<T>. InOrder calls the recursive private helper method ScanInOrder, passing to ScanInOrder the root of the tree. ScanInOrder is defined as:

IEnumerable<T> ScanInOrder(Node<T> root);

It returns the implementation of an iterator of the type IEnumerable<T>, which traverses the binary tree in order. The interesting thing about ScanInOrder is the way it uses recursion to iterate over the tree using a foreach loop that accesses the IEnumerable<T> returned from a recursive call. With in-order iteration, every node iterates over its left-side subtree, then over the value in the node itself, then over the right-side subtree. For that, you need three yield return statements. To iterate over the left-side subtree, ScanInOrder uses a foreach loop over the IEnumerable<T> returned from a recursive call that passes the left-side node as a parameter. Once that foreach loop returns, all the left-side subtree nodes have been iterated over and yielded. ScanInOrder then yields the value of the node passed to it as the root of the iteration and performs another recursive call inside a foreach loop, this time on the right-side subtree.

The InOrder property allows you to write the following foreach loop to iterate over the entire tree:

BinaryTree<int> tree = new BinaryTree<int>(); tree.Add(4,6,2,7,5,3,1); foreach(int number in tree.InOrder) { Trace.WriteLine(number); } // Traces 1,2,3,4,5,6,7

You can implement pre-order and post-order iterations in a similar manner by adding additional properties.

While the ability to use iterators recursively is obviously a powerful feature, it should be used with care as there can be serious performance implications. Each call to ScanInOrder requires an instantiation of the compiler-generated iterator, so recursively iterating over a deep tree could result in a large number of objects being created behind the scenes. In a balanced binary tree, there are approximately n iterator instantiations, where n is the number of nodes in the tree. At any given moment, approximately log(n) of those objects are live. In a decently sized tree, a large number of those objects will make it past a Generation 0 garbage collection. That said, iterators can still be used to easily iterate over recursive data structures such as trees by using explicit stacks or queues to maintain a list of nodes still to be examined.

Partial Types

C# 1.0 requires you to put all the code for a class in a single file. C# 2.0 allows you to split the definition and implementation of a class or a struct across multiple files. You can put one part of a class in one file and another part of the class in a different file by using the new partial keyword. For example, you can put the following code in the file MyClass1.cs:

public partial class MyClass { public void Method1() {...} }

In the file MyClass2.cs, you can insert this code:

public partial class MyClass { public int Number; public void Method2() {...} }

In fact, you can have as many parts as you like in any given class. Partial type support is available for classes, structures, and interfaces, but you cannot have a partial enum definition.

Partial types are a very handy feature. Sometimes it is necessary to modify a machine-generated file, such as a Web service client-side wrapper class. However, changes made to the file will be lost if you regenerate the wrapper class. Using a partial class, you can factor those changes into a separate file. ASP.NET 2.0 uses partial classes, storing the machine-generated part of the page separately in memory. Windows® Forms uses partial classes to store the visual designer output of the InitializeComponent method as well as the member controls. Partial types also enable two or more developers to work on the same type while both have their files checked out from source control without interfering with each other.

You may be asking yourself, what if the various parts define contradicting aspects of the class? The answer is simple: a class (or a struct) can have two kinds of aspects or qualities: accumulative and non-accumulative. The accumulative aspects are things that each part of the type can choose to add, such as interface derivation, properties, indexers, methods, and member variables.

For example, the following code shows how a part can add interface derivation and implementation:

public partial class MyClass {} public partial class MyClass : IMyInterface { public void Method1() {...} public void Method2() {...} }

The non-accumulative aspects are things that all the parts of a type must agree upon. Whether the type is a class or a struct, type visibility (public or internal) and the base class are non-accumulative aspects. For example, the following code does not compile because not all the parts of MyClass concur on the base class:

public class MyBase {} public class SomeOtherClass {} public partial class MyClass : MyBase {} public partial class MyClass : MyBase {} //Does not compile public partial class MyClass : SomeOtherClass {}

In addition to having all parts define the same non-accumulative parts, only a single part can override a virtual or an abstract method, and only one part can implement an interface member. Also note that any attribute that does not allow multiple applications (such as the Serializable attribute) can only be applied on a single part.

C# 2.0 supports partial types as follows: when the compiler builds the assembly, it combines from the various files the parts of a type and compiles them into a single type in Microsoft intermediate language (MSIL). The generated MSIL has no recollection which part came from which file. Just like in C# 1.0 the MSIL has no record of which file was used to define which type. Also worth noting is that partial types cannot span assemblies, and that a type can refuse to have other parts by omitting the partial qualifier from its definition.

Because all the compiler is doing is accumulating parts, a single file can contain multiple parts, even of the same type, although the usefulness of that is questionable.

In C#, developers often name a file after the class it contains and avoid putting multiple classes in the same file. When using partial types, I recommend indicating in the file name that it contains parts of a type such as MyClassP1.cs, MyClassP2.cs, or employing some other consistent way of externally indicating the content of the source file. For example, the Windows Forms designer stores its portion of the partial class for the form MyForm in a file named MyForm.Designer.cs.

Another side effect of partial types is that when approaching an unfamiliar code base, the parts of the type you maintain could be spread all over the project files. In such cases, you can use the Visual Studio Class View to display an accumulative view of all the parts of the type and to navigate through the various parts by clicking on its members. The navigation bar provides this functionality as well. You can also select Go To Definition from the context menu and, in the Find Symbol Results window, see a list of all the parts of a type in the project.

Anonymous Methods

C# supports delegates for invoking one or multiple methods. Delegates provide operators and methods for adding and removing target methods, and are used extensively throughout the .NET Framework for events, callbacks, asynchronous calls, and multithreading. However, you are sometimes forced to define a method just for the sake of using a delegate. In such cases, there is no need for multiple targets, and the code involved is often relatively short and simple. Anonymous methods is a new feature in C# 2.0 that lets you define an anonymous (that is, nameless) method called by a delegate.

For example, the following is a conventional SomeMethod method definition and delegate invocation:

class SomeClass { delegate void SomeDelegate(); public void InvokeMethod() { SomeDelegate del = new SomeDelegate(SomeMethod); del(); } void SomeMethod() {MessageBox.Show("Hello");} }

You can define and implement this with an anonymous method:

class SomeClass { delegate void SomeDelegate(); public void InvokeMethod() { SomeDelegate del = delegate() { MessageBox.Show("Hello"); }; del(); } }

The anonymous method is defined in-line and not as a member method of any class. Additionally, there is no way to apply custom attributes to an anonymous method, nor can the anonymous method define generic types or add generic constraints.

You should note two interesting things about anonymous methods: the overloaded use of the delegate reserved keyword and the delegate assignment. You will see how the compiler implements an anonymous method, but it is quite clear from looking at the code that the compiler has to infer the type of the delegate used, instantiate a new delegate object of the inferred type, wrap the new delegate around the anonymous method, and assign it to the delegate used in the definition of the anonymous method (del in the previous example).

Anonymous methods can be used anywhere that a delegate type is expected. You can pass an anonymous method into any method that accepts the appropriate delegate type as a parameter:

class SomeClass { delegate void SomeDelegate(); public void SomeMethod() { InvokeDelegate(delegate(){MessageBox.Show("Hello");}); } void InvokeDelegate(SomeDelegate del) { del(); } }

If you need to pass an anonymous method to a method that accepts an abstract Delegate parameter, such as the following

void InvokeDelegate(Delegate del);

first cast the anonymous method to the specific delegate type.

A concrete and useful example for passing an anonymous method as a parameter is launching a new thread without explicitly defining a ThreadStart delegate or a thread method:

public class MyClass { public void LauchThread() { Thread workerThread = new Thread(delegate() { MessageBox.Show("Hello"); }); workerThread.Start(); } }

In the previous example, the anonymous method serves as the thread method, causing the message box to be displayed from the new thread.

Passing Parameters to Anonymous Methods

When defining an anonymous method with parameters, you define the parameter types and names after the delegate keyword just as if it were a conventional method. The method signature must match the definition of the delegate to which it is assigned. When invoking the delegate, you pass the parameter's values, just as with a normal delegate invocation:

class SomeClass { delegate void SomeDelegate(string str); public void InvokeMethod() { SomeDelegate del = delegate(string str) { MessageBox.Show(str); }; del("Hello"); } }

If the anonymous method has no parameters, you can use a pair of empty parens after the delegate keyword:

class SomeClass { delegate void SomeDelegate(); public void InvokeMethod() { SomeDelegate del = delegate() { MessageBox.Show("Hello"); }; del(); } }

However, if you omit the empty parens after the delegate keyword altogether, you are defining a special kind of anonymous method, which could be assigned to any delegate with any signature:

class SomeClass { delegate void SomeDelegate(string str); public void InvokeMethod() { SomeDelegate del = delegate { MessageBox.Show("Hello"); }; del("Parameter is ignored"); } }

Obviously, you can only use this syntax if the anonymous method does not rely on any of the parameters, and you would want to use the method code regardless of the delegate signature. Note that you must still provide arguments when invoking the delegate because the compiler generates nameless parameters for the anonymous method, inferred from the delegate signature, as if you wrote the following (in C# pseudocode):

SomeDelegate del = delegate(string) { MessageBox.Show("Hello"); };

Additionally, anonymous methods without a parameter list cannot be used with delegates that specify out parameters.

An anonymous method can use any class member variable, and it can also use any local variable defined at the scope of its containing method as if it were its own local variable. This is demonstrated in Figure 7. Once you know how to pass parameters to an anonymous method, you can also easily define anonymous event handling, as shown in Figure 8.

Figure 8 Anonymous Method as Event Handler

public class MyForm : Form { Button m_MyButton; public MyForm() { InitializeComponent(); m_MyButton.Click += delegate(object sender,EventArgs args) { MessageBox.Show("Clicked"); }; } void InitializeComponent() {...} }

Figure 7 Local Variable in Anonymous Method Code

class SomeClass { string m_Space = " "; delegate void SomeDelegate(string str); public void MyMethod() { string msg = "Hello"; SomeDelegate del = delegate(string name) { MessageBox.Show(msg + m_Space + name); }; del("Juval"); } }

Because the += operator merely concatenates the internal invocation list of one delegate to another, you can use the += to add an anonymous method. Note that with anonymous event handling, you cannot remove the event handling method using the -= operator unless the anonymous method was added as a handler by first storing it to a delegate and then registering that delegate with the event. In that case, the -= operator can be used with the same delegate to unregister the anonymous method as a handler.

Anonymous Method Implementation

The code the compiler generates for anonymous methods largely depends on which type of parameters or variables the anonymous methods uses. For example, does the anonymous method use the local variables or parameters of its containing method (called outer variables), or does it use class member variables and method arguments? In each case, the compiler will generate different MSIL. If the anonymous method does not use outer variables (that is, it only uses its own arguments or the class members) then the compiler adds a private method to the class, giving the method a unique name. The name of that method will have the following format:

return type <containing method> + string + __ + number(params)

The method signature will be that of the delegate to which it is assigned.

The compiler then converts the anonymous method definition and assignment into a normal instantiation of the inferred delegate type, wrapping the machine-generated private method and assigning it to a cached static member of the delegate type.

Interestingly enough, the machine-generated private method does not show up in IntelliSense®, nor can you call it explicitly because the < and > in its name is an invalid token for a C# method (but are valid MSIL tokens).

The more challenging scenario is when the anonymous method uses outer variables. In that case, the compiler adds a private nested class with a unique name in the format of:

<> + string + __DisplayClass + number

The nested class has a back reference to the containing class called <>+number+__this (such as <>4__this), which is a valid MSIL member variable name. The nested class contains public member variables corresponding to every outer variable that the anonymous method uses. The compiler adds to the nested class definition a public method with a unique name, in the format of:

return type <containing method> + string + __ + number(params)

The method signature will be that of the delegate to which it is assigned. The compiler replaces the anonymous method definition with code that creates an instance of the nested class and makes the necessary assignments from the outer variables to that instance's member variables. Finally, the compiler creates a new delegate object, wrapping the public method of the nested class instance, and calls that delegate to invoke the method. Figure 9 shows in C# pseudocode the compiler-generated code for the anonymous method definition in Figure 7.

Figure 9 Anonymous Method Code with Outer Variables

class SomeClass { string m_Space = " "; delegate void SomeDelegate(string str); private sealed class <>c__DisplayClass2 { public SomeClass <>4__this; //Back pointer, name is valid in MSIL public string msg; //Outer variable public void <MyMethod>b_0(string name) { MessageBox.Show(msg + <>4__this.m_Space + name); } } public void MyMethod() { string msg = "Hello"; <>c__DisplayClass2 class1 = new <>c__DisplayClass2(); class1.<>4__this = this; class1.msg = msg; SomeDelegate del = new SomeDelegate(class1.<MyMethod>b_0); del("Juval"); }

Generic Anonymous Methods

An anonymous method can use generic parameter types, just like any other method. It can use generic types defined at the scope of the class, for example:

class SomeClass<T> { delegate void SomeDelegate(T t); public void InvokeMethod(T t) { SomeDelegate del = delegate(T item){...} del(t); } }

Because delegates can define generic parameters, an anonymous method can use generic types defined at the delegate level. You can specify the type to use in the method signature, in which case it has to match the specific type of the delegate to which it is assigned:

class SomeClass { delegate void SomeDelegate<T>(T t); public void InvokeMethod() { SomeDelegate<int> del = delegate(int number) { MessageBox.Show(number.ToString()); }; del(3); } }

Anonymous Method Examples

Although at first glance the use of anonymous methods may seem like an alien programming technique, I have found it quite useful because it replaces the need for creating a simple method in cases where only a delegate will suffice. Figure 10 shows a real-life example of the usefulness of anonymous methods—a SafeLabel Windows Forms control.

Figure 10 The SafeLabel Control

public class SafeLabel : Label { delegate void SetString(string text); delegate string GetString(); override public string Text { set { if(InvokeRequired) { SetString setTextDel = delegate(string text) { Text = text; }; Invoke(setTextDel,new object[]{value}); } else base.Text = value; } get { if(InvokeRequired) { GetString getTextDel = delegate(){ return Text; }; return (string)Invoke(getTextDel,null); } else return base.Text; } } }

Windows Forms relies on the underlying Win32® messages. Therefore, it inherits the classic Windows programming requirement that only the thread that created the window can process its messages. Calls on the wrong thread may trigger an exception. As a result, when calling to a form or a control on a different thread, you must marshal that call to the correct owning thread. Windows Forms has built-in support for solving this predicament by having the Control base class implement the interface ISynchronizeInvoke, defined as the following:

public interface ISynchronizeInvoke { bool InvokeRequired {get;} IAsyncResult BeginInvoke(Delegate method,object[] args); object EndInvoke(IAsyncResult result); object Invoke(Delegate method,object[] args); }

The Invoke method accepts a delegate targeting a method on the owning thread, and it will marshal the call to that thread from the calling thread. Because you may not always know whether you are actually executing on the correct thread, the InvokeRequired property lets you query to see if calling Invoke is required. The problem is that using ISynchronizeInvoke complicates the programming model significantly, and as a result it is often better to encapsulate the interaction with the ISynchronizeInvoke interface in controls and forms that will automatically use ISynchronizeInvoke as required.

For example, instead of a Label control that exposes a Text property, you can define the SafeLabel control which derives from Label, as shown in Figure 10. SafeLabel overrides its base class Text property. In its get and set, it checks whether Invoke is required. If so, it needs to use a delegate to access the property. That implementation recursively calls the base class implementation of the property, but on the correct thread. Because SafeLabel only defines these methods so that they can be called through a delegate, they are good candidates for anonymous methods. SafeLabel passes the delegate, wrapping the anonymous methods to the Invoke method as its safe implementation of the Text property.

Another useful example for anonymous methods are the static methods of System.Array. The System.Array type is extended with many generic static methods. The generic static methods automate and streamline common ways to work with arrays, such as iterating over the array and performing an action on each element, scanning the array looking for a value that matches a certain criteria (a predicate), converting and sorting the array, and so on. Here is a partial listing of these static methods:

public abstract class Array { //Partial listing of the static methods: public static U[] ConvertAll<T,U>(T[] array,Converter<T,U> converter); public static bool Exists<T>(T[] array,Predicate<T> match); public static T Find<T>(T[] array,Predicate<T> match); public static T[] FindAll<T>(T[] array,Predicate<T> match); public static int FindIndex<T>(T[] array,Predicate<T> match); public static void ForEach<T>(T[] array,Action<T> action); public static void Sort<T>(T[] array,Comparison<T> comparison); }

Most of these static generic methods work with the four generic delegates defined in the System namespace:

public delegate void Action<T>(T t); public delegate int Comparison<T>(T x, T y); public delegate U Converter<T, U>(T from); public delegate bool Predicate<T>(T t);

Using these delegates often requires you to define methods just so that you could wrap them with a delegate and call the methods of System.Array. This makes them a prime candidate for anonymous methods.

For example, suppose the array roles contains all the roles a user plays in your application, and you would like to find out if the user is a member of a specified role:

bool IsInRole(string role) { string[] roles = GetRoles(); Predicate<string> exists = delegate(string roleToMatch) { return roleToMatch == role; }; return Array.Exists(roles, exists); } string[] GetRoles() {...}

The Array.Exists method, defined as

public static bool Exists<T>(T[] array, Predicate<T> match);

takes a single type parameter (the array element type). The compiler can infer the type automatically, so there is no need to specify that. The second parameter is a generic delegate of type Predicate<T>, which returns a Boolean value. The Array.Exists method iterates over the array and invokes the predicate delegate on each item in the array. If the predicate returns true, it stops the iteration and returns true. If all the items in the array return false, Array.Exists returns false. You can initialize the predicate using an anonymous method, and have Array.Exists invoke that method on every item in the array until the predicate is satisfied or there are no more items. Similar methods are available on the List<T> class. These helper methods are used much the same way as the generic static methods of System.Array. The code in Figure 11 initializes a list with all the numbers from 1 to 20. Then, using the Action<T> delegate and anonymous method, the code traces these numbers using the List<T>.ForEach() method. Using the Predicate<T> delegate and an anonymous method, the code finds all the prime numbers in the list by calling the List<T>.FindAll method, which returns another list of the same type. Finally, the prime numbers are traced, using the same Action<T> delegate.

Figure 11 Streamlining List<T> with Anonymous Methods

int[] numbers = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20}; List<int> list = new List<int>(numbers); Action<int> trace = delegate(int number) { Trace.WriteLine(number); }; Predicate<int> isPrime = delegate(int number) { switch(number) { case 1:case 2:case 3:case 5:case 7: case 11:case 13:case 17:case 19: return true; default: return false; } }; list.ForEach(trace); List<int> primes = list.FindAll(isPrime); primes.ForEach(trace);

While both Array and List<T> benefit from this streamlined functionality, other collections do not. To compensate for that, the source code available with this article contains my static helper class Collection that offers this functionality (and more) for any generic collection, be it .NET-provided or a customer collection. The implementation of Collection makes extensive use of both iterators and anonymous methods.

Delegate Inference

The C# compiler's ability to infer from an anonymous method assignment which delegate type to instantiate is an important capability. In fact, it enables yet another C# 2.0 feature called delegate inference. Delegate inference allows you to make a direct assignment of a method name to a delegate variable, without wrapping it first with a delegate object. For example, take a look at the following C# 1.0 code:

class SomeClass { delegate void SomeDelegate(); public void InvokeMethod() { SomeDelegate del = new SomeDelegate(SomeMethod); del(); } void SomeMethod() {...} }

Instead of the previous snippet, you can now write:

class SomeClass { delegate void SomeDelegate(); public void InvokeMethod() { SomeDelegate del = SomeMethod; del(); } void SomeMethod() {...} }

When you assign a method name to a delegate, the compiler first infers the delegate's type. Then the compiler verifies that there is a method by that name and that its signature matches that of the inferred delegate type. Finally, the compiler creates a new object of the inferred delegate type, wrapping the method and assigning it to the delegate. The compiler can only infer the delegate type if that type is a specific delegate type—that is, anything other than the abstract type Delegate. Delegate inference is a very useful feature indeed, resulting in concise, elegant code.

I believe that as a matter of routine in C# 2.0, you will use delegate inference rather than the old method of delegate instantiation. For example, here is how you can launch a new thread without explicitly creating a ThreadStart delegate:

public class MyClass { void ThreadMethod() {...} public void LauchThread() { new Thread(ThreadMethod).Start(); } }

You can use a double stroke of delegate inference when launching an asynchronous call and providing a completion callback method, as shown in Figure 12. There you first assign the method name to invoke asynchronously into a matching delegate. Then call BeginInvoke, providing the completion callback method name instead of a delegate of type AsyncCallback.

Figure 12 Using Delegate Inference

class SomeClass { delegate void SomeDelegate(string str); public void InvokeMethodAsync() { SomeDelegate del = SomeMethod; del.BeginInvoke("Hello", OnAsyncCallBack, null); } void SomeMethod(string str) { MessageBox.Show(str); } void OnAsyncCallBack(IAsyncResult asyncResult) {...} }

Property and Index Visibility

C# 2.0 allows you to specify different visibility for the get and set accessors of a property or an indexer. For example, it is quite common to want to expose the get as public, but the set as protected. To do so, add the protected visibility qualifier to the set keyword. Similarly, you can define the set method of an indexer as protected, (see Figure 13).

Figure 13 Public Get and Protected Set

public class MyClass { string[] m_Names; public string this[int index] { get { return m_Names[index]; } protected set { m_Names[index] = value; } } //Rest of the class }

There are a few stipulations when using property visibility. First, the visibility qualifier you apply on the set or the get can only be a stringent subset of the visibility of the property itself. In other words, if the property is public, then you can specify internal, protected, protected internal, or private. If the property visibility is protected, you cannot make the get or the set public. In addition, you can only specify visibility for the get or the set, but not both.

Static Classes

It is quite common to have classes with only static methods or members (static classes). In such cases there is no point in instantiating objects of these classes. For example, the Monitor class and the ThreadPool class in the .NET Framework 1.1 are static classes. Under C# 1.0, if you want to prevent developers from instantiating objects of your class you can provide only a private default constructor on a sealed class. Without any public constructors or derivation, no one can instantiate objects of your class:

public sealed class MyClassFactory { private MyClassFactory() {} public static object CreateObject() {...} }

However, it is up to you to enforce the fact that only static members are defined on the class because the C# compiler will still allow you to add instance members, although they could never be used. C# 2.0 adds support for static classes by allowing you to qualify your class as static:

public static class MyClassFactory { public static T CreateObject<T>() {...} }

The C# 2.0 compiler will not allow you to add a non-static member to a static class, and will not allow you to create instances of the static class, just as if it were an abstract class. In addition, you cannot derive from a static class. It's as if the compiler adds both abstract and sealed to the static class definition. Note that you can define static classes but not static structures, and you can add a static constructor.

Global Namespace Qualifier

It is possible to have a nested namespace with a name that matches some other global namespace. In such cases, the C# 1.0 compiler will have trouble resolving the namespace reference. Consider the following example:

namespace MyApp { namespace System { class MyClass { public void MyMethod() { System.Diagnostics.Trace.WriteLine("Does Not Work!"); } } } }

In C# 1.0, the call to the Trace class would produce a compilation error. The reason the error would occur is that when the compiler tries to resolve the reference to the System namespace, it uses the immediate containing scope, which contains the System namespace but not the Diagnostics namespace. To address this and similar conflicts, in the .NET Framework 2.0 by default all types are rooted in a global namespace called global. For example, the following two definitions are identical:

class MyClass {} namespace global { class MyClass {} }

There is no need to add the global namespace explicitly—the compiler adds that to every type automatically, similar to derivation from System.Object.

C# 2.0 allows you to use the global namespace qualifier global:: to indicate to the compiler that it should start its search at the global scope. For example, here is how you can resolve the previously described conflict:

global::System.Diagnostics.Trace.WriteLine("It Works!");

You can apply the global:: qualifier to both namespaces and types, as shown in Figure 14.

Figure 14 Using the Global Namespace Qualifier

namespace MyApp { class MyClass { public void MyMethod() { global::MyClass obj = new global::MyClass(); obj.MyMethod(); // Traces "Hello" instead of recursion } } } public class MyClass { public void MyMethod() { Trace.WriteLine("Hello"); } }

Inline Warning

C# 1.0 allows you to disable specific compiler warnings using project settings or by issuing command-line arguments to the compiler. The problem here is that this is a global suppression, and as such suppresses warnings that you still want. C# 2.0 allows you to explicitly suppress and restore compiler warnings using the #pragma warning directive:

// Disable 'field never used' warning #pragma warning disable 169 public class MyClass { int m_Number; } #pragma warning restore 169

Disabling warnings should be generally discouraged in production code. It is intended only for analysis when trying to isolate a problem, or when you lay out the code and would like to get the initial code structure in place without having to polish it up first. In all other cases, avoid suppressing compiler warnings. Note that you cannot programmatically override the project settings, meaning you cannot use the pragma warning directive to restore a warning that is suppressed globally.

Conclusion

The new features in C# 2.0 presented in this article are dedicated solutions, designed to address specific problems while simplifying the overall programming model. If you care about productivity and quality, then you want to have the compiler generate as much of the implementation as possible, reduce repetitive programming tasks, and make the resulting code concise and readable. The new features give you just that, and I believe they are an indication that C# is coming of age, establishing itself as a great tool for the developer who is an expert in .NET.

Juval Lowy is a software architect providing consultation and training on .NET design and migration. He is also the Microsoft Regional Director for the Silicon Valley. His latest book is Programming .NET Components 2nd edition (O'Reilly, 2005). Contact Juval at www.idesign.net.