2009-12-29

if-read-do-while-read

Here’s a construction I occasionally need when reading items from a IDataReader: to execute some code before and after reading through the IDataReader, but only if there are rows in the IDataReader.

One option is to use a boolean variable that determines whether the collection has items, like this:

using (IDataReader reader = command.ExecuteReader())
{
  bool hasRows = false;
  while (reader.Read())
  {
    if (!hasRows)
    {
      hasRows = true;
      Before();
    }

    During();
  }

  if (hasRows)
    After();
}

But the following construction (which I call the if-read-do-while-read construction) does not need the boolean variable and is cleaner:

using (IDataReader reader = command.ExecuteReader())
{
  if (reader.Read())
  {
    Before();

    do
    {
      During();
    }
    while (reader.Read());

    After();
  }
}

Here's a practical example: creating HTML-code with a UL-list for the data, but only if there are items:

StringBuilder html = new StringBuilder();
using (IDataReader reader = command.ExecuteReader())
{
  if (reader.Read())
  {
    html.Append("<ul>");

    do
    {
      html.AppendFormat(
        "<li>{0}",
        reader.GetValue(0));
    }
    while (reader.Read());

    html.Append("</ul>");
  }
}

You could use the same technique on an IEnumerable<T>, but you wouldn't be able to use foreach anymore:

using (var enumerator = collection.GetEnumerator())
{
  if (enumerator.MoveNext())
  {
    Before();

    do
    {
      var item = enumerator.Current;
      During();
    }
    while (enumerator.MoveNext());

    After();
  }
}
Comments:
I bet you could clean this up nicely by using delegates and anonymous functions. The boilerplate logic could go in the primary method that called out to the delegates. However, I do like the "if" version as well, it looks very clean.
 
Tanton, I just wrote a new blog post that implements your idea as an extension method on IDataReader: http://blog.tcx.be/2010/01/if-read-do-while-read-part-2.html
 
Post a Comment

Links to this post:

Create a Link