Monday, May 19, 2008

Generic cache method

All of our code interacting with the cache is on the form

string key = "persons"
var cache = SimpleCache.Instance;
if(cache.Exists(key) && !HasExpired(Key)
{
return cache.Get(key);
}
else
{
int timeout_in_minutes = 5;
var persons = PersonDAO.GetAllPersons();
cache.Add(persons, timeout_in_minutes)
return persons;
}

---

So it's pretty tedious code to write, but relatively short and sweet. somewhat easy to introduce errors in the cache logic (which really should be the cache's responsibility after all)

I decided I would try to write one that would be easier to consume, and here is code
showing what I ended up with. The tests run as expected, I will leave it up to the reader
(if I indeed have any) to figure out how CacheFetch gets stuff done, I found it to be pretty
(yet a bit hard to grok) code that exemplifies the use of lambda-expressions and how a lambda
can access variables that were present where it was defined, in addition to those present (in the form of input params) where it is executed

--


using System.Threading;

using NUnit.Framework;

 

namespace Business.Test

{

    [TestFixture]

    public class TestLambdas

    {

        [Test]

        public void TestLamda()

        {

            var serv = new Serv();

            var s1 = serv.GetCurrentMillis();

            Thread.Sleep(20);

            var s2 = serv.GetCurrentMillis();

            Assert.AreEqual(s1, s2);

        }

 

        [Test]

        public void TestLamda2()

        {

            var serv = new Serv();

            var s1 = serv.GetRandomString(10);

            Thread.Sleep(20);

            var s2 = serv.GetRandomString(10);

            Assert.AreEqual(s1, s2);

            Thread.Sleep(20);

            var s3 = serv.GetRandomString(10);

            Assert.AreEqual(s2, s3);

        }

    }

 

    public  class Serv

    {

        public string GetRandomString(int max_rand)

        {

            return CacheFetch("rand", () => "rand"+new Random().Next(max_rand) ,5);

        }

        public int GetCurrentMillis()

        {

            return CacheFetch("day", () => DateTime.Now.Millisecond, 5);

        }

 

        public delegate T Fetch<T>();

 

        public T CacheFetch<T, K>(K key, Fetch<T> fetcher, int cacheMinutes)

        {

            var cache = SimpleCache<K, T>.Instance;

            if (cache.Exists(key) && !cache.HasExpired(key))

            {

               return cache.GetItem(key);

            }

            var retVal = fetcher();

            cache.AddItem(key, retVal, cacheMinutes);

            return retVal;

        }

    }

}