Tuesday 7 February 2012

Silverlight - Name Methods vs Anonymous Methods

Today I found myself performing a series of web service calls, all one after the other to reach the data I was after.  Lets ignore the fact that this will create many HTTP requests and the performance implications that are associated, as I was limited by the service interface being used.
Initially I broke each request into 2 methods:
  1. The call to the service to retrieve the data.
  2. The async callback method to process the data.
Initially this worked quite well, code was separated, easy to follow and quite basic.  But as time wore on, more requests were added until there were a significant amount of small methods that do only a very specific task with tight coupling to the method that called it.
Now coming from a VB.NET background this was just the way you had to do things, and you became very familiar with the AddressOf operator very quickly. Along comes C#.NET and the idea of anonymous methods to solve the problem. Most of the methods we them modified to use Anonymous Methods. This allowed all code for a single process to be encapsulated into a single method, significantly reducing the number of tightly coupled methods, greatly increasing readability and maintainability.

The following is an example of some Silverlight code before and after the change. As you can see the amount of code written has been reduced, it is more readable and maintainabled, you do not have to perform some validation as you can be certain of the data being passed in and finnally you have access to the variables within the calling method. Beware though of accessing variables within the main method as they may provide a warning of "Access to modified closure", I won't describe what that is now, too far off topic.

Before Anonymous Methods

        /// <summary>
        /// Populate the the configuration entity
        /// </summary>
        private void PopulateConfigData()
        {
            DataServiceQuery query = (DataServiceQuery<configuration>)from config in _Service.configurationSet
                                                                      select config;
 
            query.BeginExecute(new AsyncCallback(PopulateConfigData_CallBak), query);
        }
 
        /// <summary>
        /// Builds the config entity
        /// </summary>
        /// <param name="ar">Results of Async operation</param>
        private void PopulateConfigData_CallBak(IAsyncResult ar)
        {
            DataServiceQuery query = ar.AsyncState as DataServiceQuery;
 
            if (query == null)
            {
                throw new DataServiceQueryException("No configuration data returned.");
            }
 
            // load configuration information
            DataServiceCollection<configuration> results = new DataServiceCollection<configuration>(query.EndExecute(ar) as IEnumerable<configuration>);
            if (results.Count > 0)
            {
                _Config = results[0];
            }
            else
            {
                throw new DataServiceQueryException("No configuration data returned.");
            }
 
            // continue processing requests
            ContinueProcessing();
        }

After Anonymous Methods

        /// <summary>
        /// Populate the the configuration entity
        /// </summary>
        private void PopulateConfigData()
        {
            DataServiceQuery query = (DataServiceQuery<configuration>)from config in _Service.configurationSet
                                                                      select config;
 
            query.BeginExecute(result =>
                                   {
                                       // load configuration information
                                       DataServiceCollection<configuration> results = new DataServiceCollection<configuration>(query.EndExecute(result) as IEnumerable<configuration>);
                                       if (results.Count > 0)
                                       {
                                           _Config = results[0];
                                       }
                                       else
                                       {
                                           throw new DataServiceQueryException("No configuration data returned.");
                                       }
 
                                       // continue processing requests
                                       ContinueProcessing();
                                   }, null);
        }

No comments:

Post a Comment