Как создать класс, который кэширует объекты?

Я новичок в generics в С#, и я пытаюсь создать хранилище, которое другие части моей программы могут запрашивать для объектов моделей. Идея заключалась в том, что если мой класс кеша имеет объект, он проверяет его дату и возвращает его, если объект не старше 10 минут. Если он старше, то за 10 минут он загружает обновленную модель с сервера в Интернете. У него нет объекта, он загружает его и возвращает его.

Но у меня возникают проблемы с сопряжением моих объектов с DateTime, что делает его общим.

// 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;
    }
}

Ответ 1

Проверьте класс кэша памяти, доступный как часть платформы .NET http://msdn.microsoft.com/en-us/library/system.runtime.caching.memorycache.aspx

Вам нужно добавить сборку System.RunTime.Caching в качестве ссылки на ваше приложение. Ниже приведен вспомогательный класс для добавления элементов и удаления их из кеша.

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;
    }
}

Приятная вещь в том, что он потокобезопасен, и он заботится о том, чтобы автоматически закрыть кэш. Поэтому в основном все, что вам нужно сделать, это проверить, является ли получение элемента из MemoryCache нулевым или нет. Примечание однако, что MemoryCache доступен только в .NET 4.0 +

Если ваше приложение является веб-приложением, используйте System.Web.Caching, а не MemoryCache. System.Web.Caching доступен с .NET 1.1, и нет дополнительных ссылок, которые вы должны добавить в свой проект. Heres тот же вспомогательный класс для веб-страниц.

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;
    }
}

Существуют и другие политики истечения срока действия кэша, которые вы можете использовать для обоих этих шаблонов, например, кеш, основанный на пути к файлу, так что, когда файл автоматически изменяется, кеш автоматически истекает, зависит от кеша SQL (периодически выполняется опрос SQL-сервер для изменений), скользящий срок действия или вы можете создать свой собственный. Они очень полезны.