Кеширование результата исполнения метода в .NET

24.11.2009 23:41 / Артём Волк / 993 просмотра / ...

Иногда бывает необходимо кешировать результат исполнения определённого метода. Удобно, когда можно использовать достаточно универсальный способ, который подошел бы для кеширования результата выполнения произвольного кода с заранее неизвестным типом возвращаемого значения.

Идея была давным-давно где-то подсмотрена, к сожалению оригинала не удалось найти, чтобы поставить на него ссылку.

Первая часть решения. Будем использовать Generic Delegate

namespace CrispStudio.Routine
{
	public static class UtilsCache
	{
		public delegate T MethodExecution<T>();

		public static T GetCachedMethod<T>(string cacheKey, DateTime cacheExpiration, CacheDependency cacheDependencies, MethodExecution<T> method)
		{
			try
			{
				if (_context.Cache[cacheKey] == null)
				{
					_context.Cache.Insert(cacheKey,
								method(),
								cacheDependencies,
								cacheExpiration,
								Cache.NoSlidingExpiration);
				}
				return (T)_context.Cache[cacheKey];
			}
			catch
			{
				return method();
			}
		}
	}
}

Вся прелесть метода в том, что внутри анонимного делегата с уже определённой сигнатурой можно писать практически любой код, возвращающий объект заранее неизвестного методу кеширования типа.

Пример использования:

var MySlowToConstructObject = UtilsCache.GetCachedMethod(
	"KEY_IN_CACHE", 
	DateTime.Now.AddSeconds(300), 
	new CacheDependency(HostingEnvironment.MapPath("~/Web.config")),
	delegate()
			{
				/* 
					Тут можно писать практически любой код, возвращающий данные
				*/
				return DateTime.Now;
			});

Внутри делегата доступны переменные и методы, определённые за его пределами:

int x = 0;
var MySlowToConstructObject = UtilsCache.GetCachedMethod(
	"KEY_IN_CACHE", 
	DateTime.Now.AddSeconds(300), 
	new CacheDependency(HostingEnvironment.MapPath("~/Web.config")),
	delegate()
			{
				int y = x + 1;
				return y;
			});