也许这只是梦想,但是否可能创建一个属性来缓存函数的输出(如 HttpRuntime.Cache),并在函数的参数相同时返回缓存中的值,而不是实际执行函数?
当我说“函数”时,我指的是任何函数,无论它是从数据库获取数据,还是将两个整数相加,或者是输出文件的内容。任何函数。
我有同样的问题 - 我的应用程序中有多个昂贵的方法,需要对这些结果进行缓存。 以前我只是复制并粘贴了类似的代码,但后来我决定将此逻辑从我的领域中提取出来。
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; }
}
TryGetValue
)读取是否安全?插入会改变字典的内部结构,在此期间从字典读取可能(我不确定)导致未定义的行为。 - GregTryGetValue
的内部实现只是在其数组中进行迭代,并搜索适合请求值的哈希键。如果数组发生更改,则不应发生任何事情。 - Vladimir据我所知,坦率地说,不行。
但是,在框架内实现这个功能对于所有人在所有情况下都能够通用而言,这将是一个相当大的工程 - 然而,您可以通过简单地(显然,简单性是相对于需求而言的)使用抽象、继承和现有的ASP.NET Cache来定制适合自己需求的东西。
如果您想创建一个可以贴在任何方法上的[Cache]
属性(或类似属性),那么PostSharp是您的一站式解决方案。以前我使用PostSharp时,我无法忍受它会使我的构建变得非常缓慢(这是在2007年左右,所以现在可能已经不相关了)。
另一个解决方案是结合ASP.NET MVC中的Render.Partial
和OutputCaching
来使用。这是为小部件/页面区域提供HTML的绝佳解决方案。
另一个解决方案是在MVC中将您的[Cache]
属性实现为ActionFilterAttribute
。这将允许您标记控制器方法进行缓存。它只适用于控制器方法,因为AOP魔术只能在MVC管道期间与ActionFilterAttributes
一起发生。
通过ActionFilterAttribute
实现AOP已经成为我们公司的首选解决方案。
dynamic
实现这个功能是否可行。创建一个包装器,接受动态调用,调用实际对象并缓存结果。 - Matt GreerCacheable<T>
,你只需要继承它,定义一个缓存区域并给它一个lambda表达式,在缓存未命中时如何加载缓存即可。 - Chris MarisicCacheable<T>
类吗?我想看看它。 - Matt Greer