Атрибут кэширования для метода? - PullRequest
19 голосов
/ 16 марта 2011

Возможно, это сновидение, но возможно ли создать атрибут, который кэширует выходные данные функции (скажем, в HttpRuntime.Cache) и возвращает значение из кэша вместо того, чтобы фактически выполнять функцию, когда параметры передаются функции такие же?

Когда я говорю «функция», я говорю о любой функции, независимо от того, извлекает ли она данные из БД, добавляет ли она два целых числа или выплевывает содержимое файла. Любая функция.

Ответы [ 6 ]

13 голосов
/ 16 марта 2011

Ваш лучший выбор - Postsharp . Я понятия не имею, есть ли у них то, что вам нужно, но это, безусловно, стоит проверить. Кстати, обязательно опубликуйте ответ здесь, если найдете его.

РЕДАКТИРОВАТЬ: также, прибегая к помощи "кеш постшарп", дает несколько ссылок, как эта: Кэширование с C #, AOP и PostSharp

ОБНОВЛЕНИЕ: я недавно наткнулся на эту статью: Введение в кеширование на основе атрибутов . Он описывает библиотеку на основе postsharp на http://cache.codeplex.com/, если вы все еще ищете решение.

3 голосов
/ 28 марта 2011

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

    static List<News> _topNews = null;
    static DateTime _topNewsLastUpdateTime = DateTime.MinValue;
    const int CacheTime = 5;  // In minutes

    public IList<News> GetTopNews()
    {
        if (_topNewsLastUpdateTime.AddMinutes(CacheTime) < DateTime.Now)
        {
            _topNews = GetList(TopNewsCount);
        }

        return _topNews;
    }

И вот как я могу написать это сейчас:

    public IList<News> GetTopNews()
    {
        return Cacher.GetFromCache(() => GetList(TopNewsCount));
    }

Cacher - простой вспомогательный класс, вот он:

public static class Cacher
{
    const int CacheTime = 5;  // In minutes

    static Dictionary<long, CacheItem> _cachedResults = new Dictionary<long, CacheItem>();

    public static T GetFromCache<T>(Func<T> action)
    {
        long code = action.GetHashCode();

        if (!_cachedResults.ContainsKey(code))
        {
            lock (_cachedResults)
            {
                if (!_cachedResults.ContainsKey(code))
                {
                    _cachedResults.Add(code, new CacheItem { LastUpdateTime = DateTime.MinValue });
                }
            }
        }

        CacheItem item = _cachedResults[code];
        if (item.LastUpdateTime.AddMinutes(CacheTime) >= DateTime.Now)
        {
            return (T)item.Result;
        }

        T result = action();

        _cachedResults[code] = new CacheItem
        {
            LastUpdateTime = DateTime.Now,
            Result = result
        };

        return result;
    }
}


class CacheItem
{
    public DateTime LastUpdateTime { get; set; }
    public object Result { get; set; }
}

Несколько слов о Кахере. Вы можете заметить, что я не использую Monitor.Enter () (lock (...)) при вычислении результатов. Это связано с тем, что копирование указателя CacheItem (return (T) _cachedResults [code] .Result; строка) является потокобезопасной операцией - она ​​выполняется только одним ударом. Также это нормально, если несколько указателей изменят этот указатель одновременно - все они будут действительны.

1 голос
/ 16 марта 2011

PostSharp - это ваш универсальный магазин для этого, если вы хотите создать атрибут [Cache] (или аналогичный), который вы можете использовать любым способом в любом месте.Ранее, когда я использовал PostSharp, я никогда не мог понять, насколько медленно он делал мои сборки (это было еще в 2007-м, поэтому это может быть уже не актуально).

Альтернативное решение - изучить использование Render.Partial сASP.NET MVC в сочетании с OutputCaching.Это отличное решение для обслуживания html для областей виджетов / страниц.

Другое решение, которое будет с MVC, будет реализовывать ваш атрибут [Cache] как ActionFilterAttribute.Это позволит вам взять метод контроллера и пометить его для кэширования.Это будет работать только для методов контроллера, поскольку магия AOP может происходить только с ActionFilterAttributes во время конвейера MVC.

Реализация AOP с помощью ActionFilterAttribute превратилась в решение goto для моего магазина.

1 голос
/ 16 марта 2011

AFAIK, честно говоря, нет.

Но это было бы довольно непросто осуществить в рамках, чтобы оно работало в общем для всех при любых обстоятельствах, в любом случае - однако вы могли бы адаптировать что-то совершеннодостаточно просто для нужд (где, очевидно, простота относительно потребностей) с использованием абстракции, наследования и существующего ASP.NET Cache .

1 голос
/ 16 марта 2011

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

0 голосов
/ 22 мая 2012

Если вам не нужна конфигурация атрибутов, но вы принимаете конфигурацию кода, возможно MbCache - это то, что вы ищете?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...