delegates & anonymous methods - can it beat the traditional OOP ?

I want to elaborate on my main ideas from my presentation about Code Templating – abstracting your code via delegates & anonymous methods. During the presentation, I talked about solutions to repetitive, every-day tasks. One of the examples I presented was something *we are all familiar with and that is querying our database. Lets take a look shall we?


public static List<User> GetUsersList()
{
   using (SqlConnection conn = new SqlConnection(ConnectionString))
   {
      SqlCommand cmd = new SqlCommand(“Select Id, Name From Users”, conn);

      conn.Open();

      List<User> users = new List<User>();

      SqlDataReader r = cmd.ExecuteReader();
      while (r.Read())
      {
         User u = new User();
         u.Id = Convert.ToInt32(r[“Id”]);
         u.Name = Convert.ToString(r[“Name”]);

         users.Add(u);
      }

      return users;
   }
}


Now let’s imagine that we also have Get*List for Products, Orders, Items and Sales. That’s 5 Get*List methods already. Let’s look at the code that is common among those potential methods (in red):


public static List<User> GetUsersList()
{
   using (SqlConnection conn = new SqlConnection(ConnectionString))
   {

      SqlCommand cmd = new SqlCommand(“Select Id, Name From Users”, conn);

      conn.Open();

      List<User> users = new List<User>();

      SqlDataReader r = cmd.ExecuteReader();
      while (r.Read())
      {
         User u = new User();
         u.Id = Convert.ToInt32(r[“Id”]);
         u.Name = Convert.ToString(r[“Name”]);

         users.Add(u);
      }

      return users;
   }
}



So the first solution to refactor those lines of (repetitive)code out will be, obviously, via OOP.
Here is a quick solution I came up with just to make the point clear:


interface IDataReaderParser<TRet>
{
   TRet Parse(IDataReader liveReader);
}


static class DbServices
{
   public static TRet ExecuteReader<TRet>(
      IDbCommand cmd, 
      IDataReaderParser<TRet> parser)
   {
      using (SqlConnection conn = new SqlConnection(ConnectionString))
      {
         cmd.Connection = conn;

         conn.Open();

         IDataReader reader = cmd.ExecuteReader();

         return parser.Parse(reader);
      }
   }
}


So far we have some “parser” interface which will get a liveReader and return some generic type based on the required parsing. I don’t know if you’ve noticed but DbServices.ExecuteReader holds all the lines I marked with red just before. 


Let’s look at our GetUsers parser:


class GetUserListParser : IDataReaderParser<List<User>>
{
   public List<User> Parse(IDataReader liveReader)
   {
      List<User> users = new List<User>();

      while (liveReader.Read())
      {
         User u = new User();
         u.Id = Convert.ToInt32(r[“Id”]);
         u.Name = Convert.ToString(r[“Name”]);

         users.Add(u);
      }

      return users;
   }
}


Our parser get the live IDataReader and returns a list of users. Simple.
GetUsersListParser.Parse method contains the rest of the code (all code minus code in red) from our original GetUsersList method.


Finally, our GetUsersList method looks like this:


public static List<User> GetUsersList()
{
   SqlCommand cmd = new SqlCommand(“Select Id, Name From Users”);

   GetUserListParser parser = new GetUserListParser();

   return DbServices.ExecuteReader<List<User>>(cmd, parser);
}


That’s nice, but is it good enough ?? 
For every Get*List method we will have to build a separate class which will implement IDataReaderParser<TRet>. Let’s pause here.


* breath…. good …. *



Let’s rewind. When I started writing the original GetUsersList method, my main goal were those lines:


// (1) Create command
SqlCommand cmd = new SqlCommand(“Select Id, Name From Users”);

// (2) In some magical way, execute the command and return a live reader so I can parse it into objects.
List<User> users = new List<User>();

while (liveReader.Read())
{
   User u = new User();
   u.Id = Convert.ToInt32(r[“Id”]);
   u.Name = Convert.ToString(r[“Name”]);

   users.Add(u);
}

return users;



Open a connection against the database, executing the command as reader and disposing the connection were irrelevant at the time, I knew that I will have to write those lines down but they were just means to get to my real goal(=my real code). So I refactored my code via some sort of OOP solution.

Now I have pieces of code all over the place and even worse – in 1-2 months from now I will have to “Go To Definition” just to remember what the hack is GetUsersListParser class.



My main code was refactored out of my method.



Life shouldn’t be so hard. Like a very wise(and old, they are always old) programmer once said: “If you code it, it will come;”.
Let’s look at a different solution – let’s abstract our code via delegates & anonymous methods.

So our DbServices.ExecuteReader<TRet> will look like:


public delegate TRet ReaderHandler<TRet>(IDataReader liveReader);


static class DbServices
{
   public static TRet ExecuteReader<TRet>(
      IDbCommand cmd, 
      ReaderHandler<TRet> handler)
   {
      using (SqlConnection conn = new SqlConnection(ConnectionString))
      {
         cmd.Connection = conn;

         conn.Open();

         IDataReader reader = cmd.ExecuteReader();

         return handler(reader);
      }
   }
}


DbServices.ExecuteReader receive a (Sql)command to execute and an “handler” – a method with the same signature as ReaderHandler<TRet> delegate. ExecuteReader method will execute the command as a reader and send it(the reader) to the method handler. So who is this “handler” I talk about so much ?! The anonymous method !!

Let’s look at the new version of GetUsersList:


public static List<User> GetUsersList()
{
   SqlCommand cmd = new SqlCommand(“Select Id, Name From Users”);

   return DbServices.ExecuteReader<List<User>>(cmd,
      delegate(IDataReader liveReader) <– our handler, inline
      {
         List<User> users = new List<User>();

         while (liveReader.Read())
         {
            User u = new User();
            u.Id = Convert.ToInt32(liveReader[“Id”]);
            u.Name = Convert.ToString(liveReader[“Name”]);

            users.Add(u);
         }

         return users;
   });
}



The entire logic is just in front of me now, no need to start smelling around it !


Just like in the first OOP solution, I don’t need to handle the connection, call the ADO.NETs’ ExecuteReader, nothing.


To sum up:


Delegates & anonymous methods       1 : 0       OOP




Think about solutions you’ve implemented via OOP and start thinking about delegates as an alternative abstraction technique. For many straight forward architectural problems, delegates will be by far a better solution than traditional OOP.


My next post on this matter will cover the expected question – when delegates solution is too complex??


* Well, most of us anyway. For the rest of you – be cool and play along.