.NET Anonymous Methods in C#


By Shay Shivecharan
Printer Friendly Version
View My Articles

  

This article gives a brief demonstration of C# .NET's anonymous methods and the power and flexibility they offer developers in real world applications



Anonymous Methods

Download code for this article here.

The introduction of anonymous methods in C# 2.0 gives developers the ability to efficiently design code that makes use of delegates in callback situations. Prior to this language enhancement, a developer would have to define a separate method when needing to execute a callback using a delegate. Indeed, while not having to define a separate method to execute callbacks is certainly a nicety, that reason alone does not fully qualify the value of a new language feature such as anonymous methods. As we will see in the Web Resource Information Reader sample, the real benefit of anonymous methods can be seen in the flexibility it offers developers by allowing them to execute callbacks, synchronously or asynchronously, within its containing method code. When using anonymous methods, a developer can still reference local variables scoped for the containing method from within the anonymous method definition. Let's get started by showing how anonymous method in C# 2.0 has changed the way code can be written for callback situations.
 

Example using events

A simple example uses events. Consider the Application.ApplicationExit event that is raised when a Windows Forms application is closed. In .NET 1.1, one would have to define a method matching the System.EventHandler delegate signature and then attach that to the ApplicationExit event as such:
 

        public MainForm()
        {
            InitializeComponent();

            Application.ApplicationExit += new EventHandler(Application_ApplicationExit);
        }

        public void Application_ApplicationExit(object sender, EventArgs args)
        {
            // Do something before the application closes.
        }

The same code can be written as an in-line, anonymous method: 

        public MainForm()
        {
            InitializeComponent();

            Application.ApplicationExit +=
                delegate(object sender, EventArgs args)
                {
                    // Do something before the application closes.
                };
        }

As you can see, the syntax in the second part of the example saves us from having to define a separate, stand-alone method. This is the most obvious benefit of anonymous methods, but aside from aesthetics, it offers little real benefit to a developer.  Now we will take a look at a more practical example that demonstrates what I consider to be a more important benefit of anonymous methods. One of the most useful implementations of this new language feature can be seen in some of the generic collection types, including the new List<T> class. List<T> is decorated with several static methods such as Exists, Find, FindAll, Remove, and RemoveAll, all of which accept a Predicate delegate (Predicate is generic delegate that has bool as its return type). 


A more useful scenario using List<T>
 
Let's say we had an application that needed to display a list of contacts with the ability for the user to seach within this list for contacts with a specific last name. We can use the FindAll method of List<T> to do this by supplying our Predicate, which points to a callback method in our class matching the required signature. As you will see, however, since the Predicate used in FindAll accepts only a single type parameter, there is no way to pass in the last name we wish to search for (unless we cache it somewhere outside the method in a member variable...ugh). Keep in mind that a call to the callback method FindContact is made for every ContactInfo in the list.
 

        public List<ContactInfo> SearchContacts(List<ContactInfo> fullList, string lastName)
        {
            return fullList.FindAll
            (
                new Predicate<ContactInfo>(FindContact)
            );
        }

        public bool FindContact(ContactInfo contact)
        {
            // No way to match last name on passed in contact info... 
        }


Again, looking at the signature of Predicate<T>, accepted by FindAll, it is quickly apparent that is not a straightforward way to implement our search. This is where an in-line method will fit in perfectly. Modified to use an anonymous method, our code now looks like this:
 

        public List<ContactInfo> SearchContacts(List<ContactInfo> fullList, string lastName)
        {
            return fullList.FindAll
            (
                delegate(ContactInfo contact)
                {
                    return contact.LastName == lastName;
                }
            );
        }

Notice two things: first, we no longer need to define a separate method for our callback operation since we are using an in-line, anonymous method; second, inside our anonymous method, we can directly reference the lastName variable, which is scoped outside our anonymous method, to compare to the LastName property of the ContactInfo instance passed in by the List<T>.FindAll method. Again, like the FindContact method in the original version, our anonymous method is called for every ContactInfo in the list.


Anonymous and asynchronous: The Web Resource Information Reader sample

The other day, I was asked by a friend to write a simple Windows Forms application that would take a list of URLs and retrieve basic headers for each, displaying the information in a DataGridView on a Form. After writing the code, I showed it to Peter and he suggested  I make an article out of it....so here I am, writing this article and finally getting to the application that started the whole idea: The Web Resource Information Reader. T-W-R-I-R....TWRIR. I know, I know...pretty cool name :)

So anyway, back to the matter at hand. The design goal of this application was simple: Download headers from the various urls as quickly and efficiently as possible and display them back to the user. Well, when dealing with web resources, one is often at the mercy of the remote server and how efficiently it can serve our request. In this case, that could mean the user has to wait a long time to see results if say, 1 out of 6 URLs takes a long time to load. This type of scenario is always perfect for a multi-threaded solution. So for TWRIR, I use the .NET ThreadPool to run each of the URL requests. To implement this, I created a static class called Reader with a static method called GetResourcesInfo which returns a DataTable containing the length, last modified, server, and status code headers for each URL. The method takes an array of urls and a second bool parameter to indicate if we should also download the page content. For this example, I will present the entire method's code first and breakdown its pieces below:
(NOTE: I have highlighted the beginning and end lines of the anonymous method in green and the key lines of code to be discussed later in yellow)

        public static DataTable GetResourcesInfo(string[] urls, bool includeContent)
        {
            // Create DataTable for results.
            DataTable table = new DataTable();
            DataColumn contentColumn = new DataColumn("Content", typeof(string));
            DataColumn urlColumn = new DataColumn("URL", typeof(string));
            DataColumn serverColumn = new DataColumn("Server", typeof(string));
            DataColumn dateLastModifiedColumn = new DataColumn("DateLastModified", typeof(string));
            DataColumn lengthColumn = new DataColumn("Length", typeof(long));
            DataColumn statusCodeColumn = new DataColumn("StatusCode", typeof(string));
            table.Columns.AddRange(new DataColumn[] {urlColumn, serverColumn, dateLastModifiedColumn, lengthColumn, statusCodeColumn, contentColumn});

            // Create dictionary for handles stored by url.
            Dictionary<string, ManualResetEvent> handles = new Dictionary<string, ManualResetEvent>();
foreach(string url in urls) { // Add new wait handle for this url to list of handles. handles.Add(url, new ManualResetEvent(false)); ThreadPool.QueueUserWorkItem( new WaitCallback( // Define in-line method to be executed asynchronously on a ThreadPool thread. delegate(object arg) { string resourceUrl = (string)arg; // passed in url. HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(resourceUrl); HttpWebResponse response = null; request.Method = includeContent? "GET" : "HEAD";\
   
                        // Add row with default values. DataRow row = table.Rows.Add(resourceUrl, "", "", 0, "", "N/A"); try { // Try to connect to url and read response from web server. response = (HttpWebResponse)request.GetResponse(); } // If an error code is returned from the server, we still want to read // the response if there is one. We can still get it from the // WebException instance. catch(WebException ex) { response = (HttpWebResponse) ex.Response; } // Read response headers we are interested in. if(response != null) { row["Length"] = response.ContentLength.ToString(); row["Server"] = response.Server; row["StatusCode"] = response.StatusCode.ToString(); row["DateLastModified"] = response.LastModified.ToString(); // If content is requested, download data stream and add to DataRow. if (includeContent) { try
                                {
                string content =
                                     new StreamReader(response.GetResponseStream(), UTF8Encoding.UTF8).ReadToEnd();
                               row[
"Content"] = content;
                               } catch (Exception ex) { row["Content"] = ex.Message; } } response.Close(); // Closes response stream. } // Notify waiting threads that the current thread's work is done. handles[resourceUrl].Set(); }), url); } // Copy handles to array and wait for all to be signaled. ManualResetEvent[] waitArray = new ManualResetEvent[handles.Count]; handles.Values.CopyTo(waitArray, 0); WaitHandle.WaitAll(waitArray); return table; }


The first thing I do in the method is create the DataTable and DataColumn objects required to store the data I will be collecting. Since I am going to use separate threads to make each URL request, I will need a way to notify the parent thread from the child thread that its work is done. To achieve this, I create a Dictionary of thread wait handles (ManualResetEvent) and add one for each URL, using the URL as the key. Then, I call ThreadPool.QueueUserWorkItem, passing in a block of code written as an in-line method matching the signature of the WaitCallback delegate used by the ThreadPool methods. Since my in-line method code is queued up to be executed asynchronously, each ThreadPool.QueueUserWorkItem in the foreach loop returns immediately and at the end of the loop we need to use the WaitHandle class to wait for all of the queued callback requests to complete. Notice both the DataTable and the Dictionary objects are defined inside the GetResourcesInfo method, but outside of the in-line method code.
(NOTE: Understanding the basics of multi-threading are not critical to this example, but it would help. A good explanation of ThreadPool usage with wait handles can be found on MSDN)

Now, let's look at the code defined in the anonymous method passed in to the ThreadPool. Using the URL passed into the anonymous method (the variable defined as "arg"), we create an HttpWebRequest object and download the headers (a good explanation of using HttpWebRequest and HttpWebResponse can be found on CodeProject). I commented the entire method as best I could to explain what each section of code does. The key lines of code, however, are where I access variables declared outside of my in-line method:

               // Add row with default values.
               DataRow row = table.Rows.Add(resourceUrl, "", "", 0, "", "N/A");
And:

               // Notify waiting threads that the current thread's work is done.
               handles[resourceUrl].Set();

Now consider what I would have had to done to implement this without using an anonymous method. One option would have been declare static fields to "cache" my DataTable and wait handle references. However, that would have been problematic, i.e. not thread-safe, if another call to GetResourcesInfo was made from somewhere else. Another solution could be to design a separate class that has instance fields for my DataTable and wait handles and defined a GetResourcesInfo method, which is probably what I would have done had this sample been written in .NET 1.1. Of course, the whole point of this article was to introduce the concept of and demonstrate the flexibility of design offered by C# anonymous methods and I hope that my humble words and illustrations have acheived that.



Biography
I have been professionally using C# and .NET since the introduction of the first pre-beta in 2000. Since then I have been and continue to be excited about the evolution of .NET and its related technologies.

button
 
Article Discussion: Anonymous Methods
Shay Shivecharan posted at 03-Aug-07 10:32
Original Article

 
Nice. you could also mention
Peter Bromberg replied to Shay Shivecharan at 03-Aug-07 08:55
that the  WaitHandle.WaitAll(waitArray);
has overloads that allow for a timeout period. If you need 100 urls results and there are a couple that "just don't make it" (web site down, whatever) then you can use a timeout overeload to retreive what you have got so fare and not be sitting around for the next hour waiting. Nice article.

promotion
Silverlight    WPF    WCF    WWF    LINQ   
JavaScript    AJAX    ASP.NET    XAML   
C#    VB.NET    VB 6.0    GDI+    IIS    XML   
.NET Generics    Anonymous Methods    Delegate   
Visual Studio .NET    Expression Blend    Virus   
Windows Vista    Windows XP    Windows Update   
Windows 2003 Server    Windows 2008 Server   
SQL Server    Microsoft Excel    Microsoft Word   
SharePoint    BizTalk    Virtual Earth   
.NET Compact Framework    Web Service   

"Everything" RSS / ATOM Feed Parser
How to send and receive messages through message queuing in .Net
How to Read text file as database
SQL Server 2005 Paging Performance Tip
Display code of web page.
Fully Scalable Excel File Importer class for .net using Microsoft Jet driver
Generic Chart Color Manager class that can be used for any charts
Helper class to style the infragistics wingrid
Using Reflection to detemine as Assembly Info in and out.
Helper class to play with Window (Owners and position)
Resolving displayname from the culture using the XmlLanguage and LanguageSpecificStringDictionary class
Manipulate file attributes in VB.NET
Forms Based Authentication Filtered Content Editor for SharePoint
How to create a Tree View of the Windows Folder and extract all the file-folder info.
How to use AssemblyInfo.cs file in win forms to provide much needed information on Assemblies
Sorting In Datagrid
Helper class to work with NativeMethods in the native api's
Silverlight Line Of Business Applications With Offline WPF Versions
C# : Database monitoring system using XML file
C# : Adding ComboBox to ListView SubItem
Sum of Numbers Captcha: Keeping it Simple
C# Create a Piechart for the specified Hard Disk Drive Utilization
Extension Methods for DataSet and DataTable that makes tasks easier
Accessing IIS Hosted WCF Services from PHP
Helper class that provides most commonly used Extension Methods for DateTime object
Helper class to work with a Status Bar in WPF.
Finding Unmatched Records in Dataset Tables Using Linq
Silverlight Toolkit: Autocomplete TextBox Stock Symbols and Chart
COOL Auto Complete textbox using javascript
Creating a Serializable Log Entry for Microsoft Enterprise Library to log to a Database
ASP.NET Searching Values in Datagrid