Кэшировать атрибут для метода?
Возможно, это сновидение, но возможно ли создать атрибут, который кэширует вывод функции (например, в HttpRuntime.Cache) и возвращает значение из кеша вместо фактического выполнения функции, когда параметры функции одинаковы?
Когда я говорю функцию, я говорю о любой функции, независимо от того, извлекает ли она данные из БД, добавляет ли он два целых числа или выплескивает ли содержимое файл. Любая функция.
Ответы
Ответ 1
Лучше всего Postsharp. Я понятия не имею, есть ли у них то, что вам нужно, но это, безусловно, стоит проверить. Кстати, не забудьте опубликовать ответ здесь, если найдете его.
EDIT: также, googling "кеширование postsharp" дает некоторые ссылки, например: Кэширование с С#, AOP и PostSharp
UPDATE: Я недавно наткнулся на эту статью: Представление кэширования на основе атрибутов. Он описывает библиотеку на основе postharp на http://cache.codeplex.com/, если вы все еще ищете решение.
Ответ 2
У меня есть одна и та же проблема - у меня в моем приложении много дорогих методов, и мне необходимо кэшировать эти результаты. Некоторое время назад я просто скопировал аналогичный код, но потом решил отказаться от этой логики из своего домена.
Вот как я это делал раньше:
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; line) - это поточно-безопасная операция - выполняется только одним ударом. Также нормально, если более одного потока будет изменять этот указатель одновременно - все они будут действительны.
Ответ 3
Вы можете добавить словарь в свой класс, используя строку с запятой, включая имя функции в качестве ключа, и результат в качестве значения. Затем, когда ваши функции могут проверять словарь на наличие этого значения. Сохраните словарь в кеше, чтобы он существовал для всех пользователей.
Ответ 4
AFAIK, честно говоря, нет.
Но это было бы обязательным условием для реализации в рамках, чтобы оно работало в целом для всех при любых обстоятельствах. Во всяком случае, вы могли бы адаптировать что-то вполне достаточное для удовлетворения потребностей просто (где простота относительно потребностей, очевидно) с использованием абстракции, наследования и существующего кэша ASP.NET.
Ответ 5
PostSharp - это ваш единственный магазин для этого, если вы хотите создать атрибут [Cache]
(или аналогичный), который вы можете использовать любым способом в любом месте. Раньше, когда я использовал PostSharp, я никогда не мог пройти мимо того, как медленно он сделал мои сборки (это было в 2007 году, поэтому это может быть не актуально больше).
Альтернативным решением является просмотр Render.Partial
с помощью ASP.NET MVC в сочетании с OutputCaching
. Это отличное решение для обслуживания html для областей виджетов/страниц.
Другим решением, которое было бы с MVC, было бы реализовать ваш атрибут [Cache]
как ActionFilterAttribute
. Это позволит вам принять метод контроллера и пометить его кешированием. Он будет работать только для методов контроллера, так как магия АОП может возникать только с ActionFilterAttributes
во время конвейера MVC.
Реализация AOP через ActionFilterAttribute
превратилась в решение goto для моего магазина.
Ответ 6
Если вам не нужна настройка атрибута, но вы принимаете конфигурацию кода, возможно, MbCache - это то, что вы ищете?