Easy C# Memoization

I called it MagicCache at first, thinking I’d come up with something new and cool! But, as usual, I’d actually just forgotten the name.

Memoization is a useful but intrusive technique. It’s the kind of thing that I want to be able to wield around my code and put it where I need it, almost as a configuration-time parameter. So I’m not quite satisfied with just writing the code myself each time I need it. This is a perfect case for AOP.

The approach I took was not to use an existing AOP framework, since I think that would freak my coworkers out a little, but rather to do my own simple system. It uses the fantastic DynamicProxy (as do all C# AOP systems I know of) to inject code, and I use a custom attribute to mark the invocations I care about. The result is quite pleasant to work with:

[Memoize]
virtual int Sum(int a, int b)
{
    return a+b;
}

Or, in more complicated cases:

[Memoize(MaxCount=100)]
virtual object BuildObject(string paramA, int paramB)
{
    ...
}

I like this particular method because the caching policy is nicely separated from the actual logic, but has enough proximity to see what’s going on. And I don’t have to write the caching code again and again, which means I’m free to enhance the general caching algorithm.

Of course it’s not quite as easy as all that. Memoized methods must be virtual, for DynamicProxy to be able to intercept the invocation, and the object in question must be wrapped in a proxy object. In my case I wrapped it all up in a single method call, Memoizer.CreateProxy(obj). For objects that are already built in a factory this is not problem at all, but sometimes it’s kind of inconvenient.

I’ve also added the ability to treat returned strings as paths to files which are deleted when they are removed from the cache, though I haven’t thought through it well enough to be generally useful.

Technorati Tags: , ,

Advertisements

3 thoughts on “Easy C# Memoization

  1. Hi Russel,

    I’m curious about your implementation.

    I’m trying to make a Memoization Aspect using PostSharp Laos and I have some concerns that you might have encountered while designing your DynamicProxy approach.

    Here are my concerns :

    – Do I allow only value type arguments.

    If reference type are accepted there are some nasty things to consider. The best solution might be to clone the object, but requiring ICloneable is a boring limitation.

    – Can a memoized method rely on instance fields to process its result.

    If instance field can be used in the memoized method, the instance would need to be cloned and added in the Memoization cache, which again require ICloneable on the instance.

    Any comments on how you approached these concerns would be welcome.

    Thanks

    Jeff C.

  2. Jeff:

    It’s probably prudent to do only value types. My implementation just used a combined hash of the parameters. Which I just realized, thinking through your question, is prone to collisions. I’ll have to re-examine that code.

    w.r.t. instance fields: I ignored them. They can be counted as inputs to the method, but that gets complicated fast. My version supports only plain functions with no side effects, where the only inputs are given as formal parameters.

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s