C# 方法的缓存属性?
也许这是在做梦,但是有没有可能创建一个属性来缓存函数的输出(比如,在HttpRuntime.Cache中)并从缓存返回值,而不是在函数的参数相同时实际执行函数 当我说函数时,我指的是任何函数,无论它是从数据库中获取数据,还是添加两个整数,还是吐出文件的内容。任何功能。您的最佳选择是。我不知道他们是否有你需要的东西,但这确实值得检查。顺便说一下,如果你找到答案,一定要在这里公布 编辑:此外,谷歌搜索“postsharp缓存”会提供一些链接,如以下链接:C# 方法的缓存属性?,c#,.net,asp.net,caching,C#,.net,Asp.net,Caching,也许这是在做梦,但是有没有可能创建一个属性来缓存函数的输出(比如,在HttpRuntime.Cache中)并从缓存返回值,而不是在函数的参数相同时实际执行函数 当我说函数时,我指的是任何函数,无论它是从数据库中获取数据,还是添加两个整数,还是吐出文件的内容。任何功能。您的最佳选择是。我不知道他们是否有你需要的东西,但这确实值得检查。顺便说一下,如果你找到答案,一定要在这里公布 编辑:此外,谷歌搜索“postsharp缓存”会提供一些链接,如以下链接: 更新:我最近偶然发现了这篇文章:。它描述了一
更新:我最近偶然发现了这篇文章:。它描述了一个基于postsharp的库,如果您仍在寻找解决方案。您可以使用逗号分隔的字符串将字典添加到类中,该字符串包括函数名作为键,结果作为值。然后,当您的函数可以检查字典中是否存在该值时。将字典保存在缓存中,以便所有用户都可以使用它。好的,坦白说,没有
但这将是一项在框架内实现的任务,以使其在所有情况下都能为每个人通用-然而,您可以通过简单地(显然,简单性与需求相关)使用抽象来定制一些足以满足需求的东西,继承和现有。如果您想创建一个
[Cache]
属性(或类似属性),您可以在任何地方使用任何方法,那么PostSharp就是您的一站式解决方案。以前,当我使用PostSharp时,我无法克服它使我的构建速度有多慢(这是在2007年,所以这可能不再相关)
另一种解决方案是将ASP.NET MVC中的Render.Partial
与OutputCaching
结合使用。这是为小部件/页面区域提供html的一个很好的解决方案
MVC的另一个解决方案是将[Cache]
属性实现为ActionFilterAttribute
。这将允许您获取控制器方法并将其标记为缓存。它只适用于控制器方法,因为AOP魔术只能在MVC管道中使用ActionFilterAttributes
通过
ActionFilterAttribute
实现AOP已经成为我的商店的goto解决方案。我也有同样的问题-我的应用程序中有很多昂贵的方法,我有必要缓存这些结果。不久前,我只是复制粘贴的类似代码,但后来我决定将此逻辑排除在我的域之外。
我以前就是这样做的:
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;
}
静态列表_topNews=null;
静态DateTime\u topNewsLastUpdateTime=DateTime.MinValue;
常量int CacheTime=5;//几分钟后
公共IList GetTopNews()
{
如果(\u topNewsLastUpdateTime.AddMinutes(CacheTime)
这就是我现在可以写的:
public IList<News> GetTopNews()
{
return Cacher.GetFromCache(() => GetList(TopNewsCount));
}
public IList GetTopNews()
{
返回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; }
}
公共静态类缓存器
{
const int CacheTime=5;//以分钟为单位
静态字典_cachedResults=新字典();
公共静态T GetFromCache(函数操作)
{
long code=action.GetHashCode();
if(!\u cachedResults.ContainsKey(代码))
{
锁定(缓存结果)
{
if(!\u cachedResults.ContainsKey(代码))
{
_Add(代码,新的CacheItem{LastUpdateTime=DateTime.MinValue});
}
}
}
CacheItem项目=_cachedResults[代码];
if(item.LastUpdateTime.AddMinutes(CacheTime)>=DateTime.Now)
{
返回(T)项结果;
}
T结果=动作();
_cachedResults[代码]=新的CacheItem
{
LastUpdateTime=日期时间。现在,
结果=结果
};
返回结果;
}
}
类缓存项
{
公共日期时间LastUpdateTime{get;set;}
公共对象结果{get;set;}
}
关于Cacher的几句话。您可能会注意到,我在计算结果时不使用Monitor.Enter()(lock(…)。这是因为复制CacheItem指针(return(T)\u cachedResults[code].Result;line)是线程安全的操作-只需一个笔划即可执行。另外,如果多个线程同时更改此指针也可以-它们都将有效。如果您不需要属性配置,但接受代码配置,那么这可能就是您想要的吗?可能您正在谈论模拟?我想知道使用
动态
实现这一点有多可行。创建一个包装器,该包装器接受动态调用,调用实际对象并缓存来自它们的结果。@Matt Greer您不需要动态来实现类似的目标,因为您已经接受放弃使用AOP。我创建了一个基类Cacheable
,您所要做的就是从它继承,定义一个缓存区域,并给它一个lambda语句,说明如何在缓存未命中时加载缓存。@Chris Marisic--您介意共享您的Cacheable
类吗?我想看看。@PostgresQLNewb:我用今天找到的一个新链接更新了我的旧答案,以防万一你仍然对这个东西感兴趣。无论如何,函数名对于键显然是不够的,我认为它必须依赖于参数。但是我很确定在方法的开头添加普通的缓存/检索代码不是OP想要的,但是当另一个线程插入值时,从字典中读取(TryGetValue
)是线程安全的吗?在