Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I create a class that caches objects?

Tags:

c#

Im new to generics in c#, and I'm trying to create a storage that other parts of my program can ask for models objects. The idea was that if my cache class has the object, it checks its date and returns it if the object is not older then 10 min. If it is older then 10 min it downloads a updated model from the server online. It it does not have the object is downloads it and returns it.

But I'm having some problems pairing my objects with a DateTime, makeing it all generic.

// model
public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        Person p = new Person();

        Cache c = new Cache();

        p = c.Get<Person>(p);
    }
}

public class Cache
{
    struct DatedObject<T>
    {
        public DateTime Time { get; set; }
        public T Obj { get; set; }
    }

    List<DatedObject<T>> objects;

    public Cache() 
    {
        objects = new List<DatedObject<T>>();
    }

    public T Get<T>(T obj)
    {
        bool found = false;

        // search to see if the object is stored
        foreach(var elem in objects)
            if( elem.ToString().Equals(obj.ToString() ) )
            {
                // the object is found
                found = true;

                // check to see if it is fresh
                TimeSpan sp = DateTime.Now - elem.Time;

                if( sp.TotalMinutes <= 10 )
                    return elem;
            }


        // object was not found or out of date

        // download object from server
        var ret = JsonConvert.DeserializeObject<T>("DOWNLOADED JSON STRING");

        if( found )
        {
            // redate the object and replace it in list
            foreach(var elem in objects)
                if( elem.Obj.ToString().Equals(obj.ToString() ) )
                {
                    elem.Obj = ret;
                    elem.Time = DateTime.Now;
                }
        }
        else
        {
            // add the object to the list
            objects.Add( new DatedObject<T>() { Time = DateTime.Now, Obj = ret });                
        }

        return ret;
    }
}
like image 500
Jason94 Avatar asked Aug 12 '13 07:08

Jason94


1 Answers

Check out the memory cache class available as part of the .NET framework http://msdn.microsoft.com/en-us/library/system.runtime.caching.memorycache.aspx

You'll need to add the System.RunTime.Caching assembly as a reference to your application. The following is a helper class to add items and remove them from cache.

using System;
using System.Runtime.Caching;

public static class CacheHelper
{
    public static void SaveTocache(string cacheKey, object savedItem, DateTime absoluteExpiration)
    {
        MemoryCache.Default.Add(cacheKey, savedItem, absoluteExpiration);
    }

    public static T GetFromCache<T>(string cacheKey) where T : class
    {
        return MemoryCache.Default[cacheKey] as T;
    }

    public static void RemoveFromCache(string cacheKey)
    {
        MemoryCache.Default.Remove(cacheKey);
    }

    public static bool IsIncache(string cacheKey)
    {
        return MemoryCache.Default[cacheKey] != null;
    }
}

The nice thing about this is that it's thread safe, and it takes care of expiring the cache automatically for you. So basically all you have to do is check if getting an item from MemoryCache is null or not. Note however that MemoryCache is only available in .NET 4.0+

If your application is a web application then use System.Web.Caching rather than MemoryCache. System.Web.Caching has been available since .NET 1.1 and there's no additional references you have to add to your project. Heres the same helper class for web.

using System.Web;

public static class CacheHelper
{
    public static void SaveTocache(string cacheKey, object savedItem, DateTime absoluteExpiration)
    {
        if (IsIncache(cacheKey))
        {
            HttpContext.Current.Cache.Remove(cacheKey);
        }

        HttpContext.Current.Cache.Add(cacheKey, savedItem, null, System.Web.Caching.Cache.NoAbsoluteExpiration, new TimeSpan(0, 10, 0), System.Web.Caching.CacheItemPriority.Default, null);
    }

    public static T GetFromCache<T>(string cacheKey) where T : class
    {
        return HttpContext.Current.Cache[cacheKey] as T;
    }

    public static void RemoveFromCache(string cacheKey)
    {
        HttpContext.Current.Cache.Remove(cacheKey);
    }

    public static bool IsIncache(string cacheKey)
    {
        return HttpContext.Current.Cache[cacheKey] != null;
    }
}

There are other cache expiration policies that you can use for both of these patterns, for instance cache based on a file path(s) so that when a file changes the cache automatically expires, SQL cache dependency (does periodic polling of the SQL server for changes), sliding expiration or you could build your own. They come in really handy.

like image 152
nerdybeardo Avatar answered Oct 22 '22 15:10

nerdybeardo