Welcome to WindowsClient.net | Sign in | Join

October 2008 - Posts

We all have coding patterns that we like, and use a lot. Some of them can be quite laborious, though, so if you're anything like me you'll be looking for shortcuts. C++ programmers have a powerful macro language that can provide a shorthand for a complicated block of code, which is then expanded during the compile process. C# doesn't have a macro language, but using anonymous delegates and closures, it is possible to achieve something similar, maybe even better. I've come up with a few little tricks in this area, so I'm going to share them here over the next few updates.

This example looks at an optimisation technique wherein the return values from slow-running deterministic methods (i.e. methods which, given a certain parameter, will always return the same value) are cached locally, and returned from the cache on subsequent calls. The pattern looks like this:

public class Example
{
  private Dictionary<Uri, string> cache = new Dictionary<Uri, string>();
  private object lockObject = new object();

  public string GetFromWeb(Uri uri)
  {
    if (!cache.ContainsKey(uri)) // Check cache
    {
      lock (lockObject) // Thread safety!
      {
        // Check cache again in case key was added while waiting for lock
        if (!cache.ContainsKey(uri))
        {
          // Process request
          var webClient = new WebClient();
          var reader = new StreamReader(webClient.OpenRead(uri));

          // Add result to cache
          cache.Add(uri, reader.ReadToEnd());
        }
      }
    }

    // Return cached value
    return cache[uri];
  }
}

In this - admittedly simple - example, that's a poor ratio of boilerplate to actual code. On top of that, we've had to declare a couple of variables in the containing class which exist only to facilitate this optimisation pattern in this method. After typing out this pattern dozens of times (well, at least ten. OK, five. Fine, it was twice, I get bored quickly) I wondered if there was a better way. And there is.

First off, let's refactor the code above to extract the three lines that are actually doing the work and put them in their own method:

public class Example
{
  private Dictionary<Uri, string> cache = new Dictionary<Uri, string>();
  private object lockObject = new object();

  public string GetFromWeb(Uri uri)
  {
    if (!cache.ContainsKey(uri)) // Check cache
    {
      lock (lockObject) // Thread safety!
      {
        // Check cache again in case key was added while waiting for lock
        if (!cache.ContainsKey(uri))
        {
          // Add result to cache
          cache.Add(uri, ProcessRequest(uri));
        }
      }
    }

    // Return cached value
    return cache[uri];
  }

  private string ProcessRequest(Uri uri)
  {
    var webClient = new WebClient();
    var reader = new StreamReader(webClient.OpenRead(uri));

    // Add result to cache
    return reader.ReadToEnd();
  }
}

That's better code, for a start, but it also shows that all we're doing is storing the return value from a method in a dictionary, using the parameter as a key. If we represent the method as a Func delegate, it will have the exact same type parameters as the dictionary used for the cache. So we can create a generic wrapper around the method which handles all the boilerplate code, and just concentrate on our application logic.

We could create a class which exposed a Func<T, TReturn> and held the dictionary internally, but there's a feature in C# (since 2.0) which means we don't even need to do that: closures. Closures mean that when you create an anonymous method, any locally-scoped variables referenced by the method are bundled up with it automatically by the compiler in a generated class that you don't have to worry about.

This means we can just create a new delegate wrapped around the method we want to cache, and bundle its dictionary in with it as a closure. We can do this using a utility method which will work with any method matching the Func<T,TResult> delegate signature:

public static class MethodCacher
{
  public static Func<T, TResult> MakeCached<T, TResult>(Func<T, TResult> func)
  {
    // cache and lockObject will be bundled into the delegate as closures.
    var cache = new Dictionary<T, TResult>();
    var lockObject = new object();

    Func<T, TResult> cachedFunc = (arg) =>
        {
          if (!cache.ContainsKey(arg)) // check for cached value
          {
            lock (lockObject) // exclusive lock
            {
              if (!cache.ContainsKey(arg)) // re-check after obtaining lock
              {
                cache.Add(arg, func(arg)); // add return value from wrapped delegate to cache
              }
            }
          }

          return cache[arg];
        };

    return cachedFunc;
  }
}

You can use this utility method to create caching versions of methods you don't have the source for, or to switch caching on and off easily, maybe depending on the quality of network connection. A full example of this use is available from my MSDN Code Gallery page.

I hope this has been interesting and/or informative, and I'll post something in a similar vein soonish.

There's been a lot of discussion around type inference and the var keyword in C# 3.0 since it was released. Personally I'm a fan, as I never enjoyed having to type things like
 
using (SqlDataReader reader = cmd.ExecuteReader())
 
(Intellisense is great, but there are so many types that start with "SqlData" that it was still annoying.)
 
Anyway, I'm working on a business object framework at the moment, have been for a long time, and as I go along I refactor a lot for best practices. I've just been through and looked at all the methods that return arrays to check whether that's actually the most appropriate type; usually, it isn't. I found a lot of places where the only functionality possibly required by the consumers was iteration or LINQ-related, meaning the correct return type was IEnumerable<T>. Since, for example, "string[]" implements IEnumerable<string>, I could very quickly change the return type of the method and worry about the implementation, if necessary, later.
 
In about half the instances where I made this change, the references to the method elsewhere in the code were pre-C# 3.0, so they explicitly used the array type as the variable declaration and I had to go through and change them. Naturally, I changed them to var, which was a hell of a lot easier than specifying the actual IEnumerable<T> in every case.
 
In the other half of the references to these methods, the ones written post-C# 3.0, I'd used var already. And in all except one case, after I'd changed the return type of the method, the calling code required no modification at all. That one case involved a "x.Length > 0" check and an "IndexOf(x,y) > -1", which were pointed up via compilation errors and swiftly changed to "x.Any()" and "x.Contains(y)".
 
So, to the extent that consumers are less interested in the specific type being returned than in the properties and methods it exposes, using type inference can make refactoring considerably easier. That's a good argument for me.
 
Page view counter