Sponsored By Aspose - File Format APIs for .NET

Aspose are the market leader of .NET APIs for file business formats – natively work with DOCX, XLSX, PPT, PDF, MSG, MPP, images formats and many more!

Get Your Func On

I’ve noticed that I have a 2 step pattern for learning new framework or language features. I’m guessing this is pretty typical for most people. First, I’ll use the feature within framework classes or 3rd party ddls. Then I’ll leverage it more directly within my own code. What’s surprising to me is the length of time which occurs between step 1 and step 2.


Take generics for example. Back in the 1.x days, I wrote a ton of repetitive classes that inherited from CollectionBase. So when 2.0 came out, I immediately and aggressively started to use generic collections. However, it was quite some time later (a year?) until I wrote my own class that leveraged them directly. Today, I don’t write a new generic class every day, but I do consider them an important part of my toolbox and kinda wonder what took me so long to take them up.


I have a feeling that many developers are in the same boat – it’s easy to consume code that implements new features, but not so easy to grasp how to implement those same features ourselves.


As it turns out, the other day, I had another such ah-hah moment with the System.Func generic delegate. Like me, you’ve probably consumed it often, or at least one of its cousins: System.Action and System.Predicate. I thought I’d show how I used it, in hopes that it might open up some possibilities for you.


Ovewview


First though, a brief overview. The three delegates above are essentially shortcuts that save you from having to write your own common delegate. The most common one is probably Predicate<T>, which returns a boolean. Predicte<T> is used extensively by the List<T> and Array classes. The most obvious is the Exist method:

List<string> roles = user.Roles;
if (roles.Exists(delegate(string r) { return r == “admin”;}))
{
//do something
}

or the lambda version (which I much prefer)

if (role.Exists(r => r == “admin))
{
}

Func<T> is a lot like Predicate, but instead of returning a boolean it returns T. Also, Func<T> has multiple overloads that let you pass 0 to 4 input parameters into the delegate. Action<T> is like Func<T> except it doesn’t return anything – it does an action.


Code Decoupling


So, how can you make use of these within your own code? Well, here’s what I did. First, I’m a big proponent of caching, as well as a big fan of unit testing. However, the two don’t easily go hand-in-hand because Microsoft doesn’t provide an interface to their built-in cache, which leads to tight coupling (which of course makes it difficult to change caching implementation down the road, and impossible to unit test). The first thing to do is create your own interface, a simple start might look like:

public interface ICacheManager
{
T Get<T>(string key);
void Insert(string key, object value);
}

Next comes our first implementation:

public class InMemoryCacheManager : ICacheManager
{
public T Get<T>(string key)
{
return (T) HttpRuntime.Cache.Get(key);
}
public void Insert(string key, object value)
{
HttpRuntime.Cache.Insert(key, value);
}
}

Func Fights Repitition


So, what does all this have to do with System.Func? Well, the above code is used in a very repetitive manner: get the value from the cache, if it’s null, load it from somewhere and put it back in the cache. For example:

public User GetUserFromId(int userId)
{
ICacheManager cache = CacheFactory.GetInstance;
string cacheKey = string.Format(“User.by_id.{0}”, userId);
User user = cache.Get(cacheKey);
if (user == null)
{
user = _dataStore.GetUserFromId(userId);
cache.Insert(cacheKey, user);
}
return user;
}

After a year or so of writing code like this, I figured there must be a better way, which of course is where Func comes in. Ideally, we’d like to get the value, and provide our callback code all at once. So, let’s change our interface:

public interface ICacheManager
{
T Get<T>(string key, Func<T> callback);
void Insert(string key, object value);
}

The second parameter is the delegate we’ll want to execute if Get returns null. Of course our delegate will return the same type (T) as Get would – just like in the above case where we expect a User from both Get and our data store. Here’s the actual implementation:

public T Get<T> (string key, Func<T> callback)
{
T item = (T) HttpRuntime.Cache.Get(key);
if (item == null)
{
item = callback();
Insert(key, item);
}
return item;
}

How do we use the above code?

public User GetUserFromId(int userId)
{
return CacheFactory.GetInstance.Get(string.Format(“User.by_id.{0}”, userId),
() => _dataStore.GetUserFromId(userId));
}

I know the () => syntax might be intimidating (especially if you aren’t familiar with lambdas), but all it is is a parameterless delegate.


Of course, this system can easily be expanded to add additional caching instructions (absolute/sliding expiries, dependencies and so on) via overloaded Get<T> and Insert members.


(I just noticed this example also highlights how to use generics within your own code too!)

This entry was posted in Uncategorized. Bookmark the permalink. Follow any comments here with the RSS feed for this post.

7 Responses to Get Your Func On

  1. Rafael Rosa Fu says:

    Hi, very interesting post, as always.

    I’d like to thank you for your Foundations of Programming series, which I noticed quite some ago but only had time to read them carefully this weekend, in the e-book format. The topics you picked are very important, and I really like the way you explain them. Even though I’m a seasoned programmer (13+ years) reading all that stuff in a structured way helped me settle some doubts about stuff I’ve been studying recently, like TDD and ORM. I’ll ask my trainee to read it, and hopefully she will learn things I’m not sure I know how to explain (I’m a lousy teacher), even though many of them are easier to understand when we have some experience doing things the old-hard-clumsy way :)

    Thanks a lot,
    Rafael
    São Paulo – Brazil

  2. jbland says:

    i saw the same pattern in a collaborative filtering library i ported from Java. It had pluggable data backends, so the cache was implemented similarly as you presented. The callback was called fetcher, FWIW

  3. As always, nice post!

  4. Excellent example!

    I was looking for good Func descriptions and examples. More! More!

  5. karl says:

    Good call Todd.

    I think I like Func ifNull or something simpler. I originally named it block, influenced by rails, tried to pick a more NETish name, but I agree callback is still vague..makes it sound like Get is asynchronous or something…

  6. Todd says:

    Good article. Just one suggestion.

    callback is a horrible parameter name. It’s not descriptive at all and you have to look at the implementation to know what it does. How about valueIfNull?

  7. Very interesting article, thanks.