0

我有一个调用外部 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;
}
4

1 回答 1

0

这是因为您正在使用 List 集合类型。列表提供对当前集合的引用。如果您不想修改缓存集合,则必须复制您的集合并运行过滤器。或者从不允许修改当前集合的缓存中返回 ienumarable 并执行过滤器之类的必要操作。

如果你需要它的例子,请告诉我。

于 2013-01-29T05:48:58.460 回答