我有一个调用外部 API 来获取数据的 MVC 3 应用程序。API 返回 XML,然后我将其序列化为对象。其中一些对象在一天中不会更改,因此我将它们缓存以减少开销。我的问题是,如果我从缓存中取出一个项目并对其进行操作,它也会更改缓存的值。我认为这是因为只返回对缓存项的引用。我正在使用 System.Web.HttpRuntime.Cache 来缓存对象。有没有办法将缓存中的项目作为不可变对象返回?或者轻松返回对象的克隆?我尝试将缓存的值反序列化回 XML,然后将其序列化为一个新对象,尽管这可行,但它增加了很多开销,并导致站点在负载下执行得很差。我可以为每个项目实现 ICloneable,但是随后我必须为我的每个类编写一个深度克隆方法,这将花费大量时间,并且可能会产生与序列化相同的开销问题。我想知道是否有更快的方法。
可以说我有一个缓存的人员列表。如果我这样做:
var people = Cache.Get<List<Person>>("people");
people.Remove(p => p.LastName != "Smith");
return View(people);
这将从视图和缓存列表中删除姓氏不是 Smith 的所有人员。该项目的未来获取将只返回史密斯。
我可以通过这样做来解决这个问题:
var people = Cache.Get<List<Person>>("people");
var viewlist = people.Where(p => p.LastName == "Smith").ToList();
return View(viewlist);
这不会影响缓存的值。显然,我可以在代码中的任何地方执行此操作,但考虑到我缓存的项目数量,我必须确保每次都执行此操作。如果我尝试编辑从缓存中获取的对象,如果我可以让代码抛出编译时(甚至是运行时)错误,那就更好了。
我的缓存方法:
static object lockobj = new object();
public static T Get<T>(string index) //where T : new()
{
T data;
lock (lockobj)
{
data = (T)_cache[index];
}
return data;
}
public static T CacheInsert<T>(T obj, string index, CacheDependency dependencies,
DateTime absoluteExpiration, TimeSpan slidingExpiration,
CacheItemPriority priority, CacheItemRemovedCallback callback)
{
T data;
lock (lockobj)
{
data = (T)_cache[index];
if (data == null)
{
_cache.Insert(index, obj, dependencies, absoluteExpiration, slidingExpiration, priority, callback);
data = obj;
}
}
return data;
}