- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我目前正在尝试 .Net 4 中的新 MemoryCache
以在我们的一个应用程序中缓存一些数据。我遇到的问题是对象已更新并且缓存似乎正在保留更改,例如
public IEnumerable<SomeObject> GetFromDatabase(){
const string _cacheKeyGetDisplayTree = "SomeKey";
ObjectCache _cache = MemoryCache.Default;
var objectInCache = _cache.Get(_cacheKeyGetDisplayTree) as IEnumerable<SomeObject>;
if (objectInCache != null)
return objectInCache.ToList();
// Do something to get the items
_cache.Add(_cacheKeyGetDisplayTree, categories, new DateTimeOffset(DateTime.UtcNow.AddHours(1)));
return categories.ToList();
}
public IEnumerable<SomeObject> GetWithIndentation(){
var categories = GetFromDatabase();
foreach (var c in categories)
{
c.Name = "-" + c.Name;
}
return categories;
}
如果我先调用 GetWithIndentation()
然后再调用 GetFromDatabase()
我希望它返回 SomeObject
的原始列表但它会返回修改后的项目(名称前带有“-”前缀)。
我以为 ToList()
破坏了引用,但它似乎仍然保留更改。我敢肯定这很明显,但有人能发现我哪里出错了吗?
最佳答案
我创建了一个 ReadonlyMemoryCache 类来解决这个问题。它继承自 .NET 4.0 MemoryCache,但对象以只读方式(按值)存储且无法修改。我在使用二进制序列化存储之前深度复制对象。
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Runtime.Caching;
using System.Runtime.Serialization.Formatters.Binary;
using System.Threading.Tasks;
namespace ReadOnlyCache
{
class Program
{
static void Main()
{
Start();
Console.ReadLine();
}
private static async void Start() {
while (true)
{
TestMemoryCache();
await Task.Delay(TimeSpan.FromSeconds(1));
}
}
private static void TestMemoryCache() {
List<Item> items = null;
string cacheIdentifier = "items";
var cache = ReadonlyMemoryCache.Default;
//change to MemoryCache to understand the problem
//var cache = MemoryCache.Default;
if (cache.Contains(cacheIdentifier))
{
items = cache.Get(cacheIdentifier) as List<Item>;
Console.WriteLine("Got {0} items from cache: {1}", items.Count, string.Join(", ", items));
//modify after getting from cache, cached items will remain unchanged
items[0].Value = DateTime.Now.Millisecond.ToString();
}
if (items == null)
{
items = new List<Item>() { new Item() { Value = "Steve" }, new Item() { Value = "Lisa" }, new Item() { Value = "Bob" } };
Console.WriteLine("Reading {0} items from disk and caching", items.Count);
//cache for x seconds
var policy = new CacheItemPolicy() { AbsoluteExpiration = new DateTimeOffset(DateTime.Now.AddSeconds(5)) };
cache.Add(cacheIdentifier, items, policy);
//modify after writing to cache, cached items will remain unchanged
items[1].Value = DateTime.Now.Millisecond.ToString();
}
}
}
//cached items must be serializable
[Serializable]
class Item {
public string Value { get; set; }
public override string ToString() { return Value; }
}
/// <summary>
/// Readonly version of MemoryCache. Objects will always be returned in-value, via a deep copy.
/// Objects requrements: [Serializable] and sometimes have a deserialization constructor (see http://stackoverflow.com/a/5017346/2440)
/// </summary>
public class ReadonlyMemoryCache : MemoryCache
{
public ReadonlyMemoryCache(string name, NameValueCollection config = null) : base(name, config) {
}
private static ReadonlyMemoryCache def = new ReadonlyMemoryCache("readonlydefault");
public new static ReadonlyMemoryCache Default {
get
{
if (def == null)
def = new ReadonlyMemoryCache("readonlydefault");
return def;
}
}
//we must run deepcopy when adding, otherwise items can be changed after the add() but before the get()
public new bool Add(CacheItem item, CacheItemPolicy policy)
{
return base.Add(item.DeepCopy(), policy);
}
public new object AddOrGetExisting(string key, object value, DateTimeOffset absoluteExpiration, string regionName = null)
{
return base.AddOrGetExisting(key, value.DeepCopy(), absoluteExpiration, regionName);
}
public new CacheItem AddOrGetExisting(CacheItem item, CacheItemPolicy policy)
{
return base.AddOrGetExisting(item.DeepCopy(), policy);
}
public new object AddOrGetExisting(string key, object value, CacheItemPolicy policy, string regionName = null)
{
return base.AddOrGetExisting(key, value.DeepCopy(), policy, regionName);
}
//methods from ObjectCache
public new bool Add(string key, object value, DateTimeOffset absoluteExpiration, string regionName = null)
{
return base.Add(key, value.DeepCopy(), absoluteExpiration, regionName);
}
public new bool Add(string key, object value, CacheItemPolicy policy, string regionName = null)
{
return base.Add(key, value.DeepCopy(), policy, regionName);
}
//for unknown reasons, we also need deepcopy when GETTING values, even though we run deepcopy on all (??) set methods.
public new object Get(string key, string regionName = null)
{
var item = base.Get(key, regionName);
return item.DeepCopy();
}
public new CacheItem GetCacheItem(string key, string regionName = null)
{
var item = base.GetCacheItem(key, regionName);
return item.DeepCopy();
}
}
public static class DeepCopyExtentionMethods
{
/// <summary>
/// Creates a deep copy of an object. Must be [Serializable] and sometimes have a deserialization constructor (see http://stackoverflow.com/a/5017346/2440)
/// </summary>
public static T DeepCopy<T>(this T obj)
{
using (var ms = new MemoryStream())
{
var formatter = new BinaryFormatter();
formatter.Serialize(ms, obj);
ms.Position = 0;
return (T)formatter.Deserialize(ms);
}
}
}
}
关于c# - 如何分离 MemoryCache 上的对象引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13934710/
我读了MSDN documentation但并没有真正理解它。 我相信Set的行为是“替换现有的,或添加”(原子地)。 正确吗? 最佳答案 如果该键已存在值, Add 不会执行任何操作(返回 fals
我试图找到一种方法让 .net 4.0 MemoryCache.Default 实例使用不区分大小写的比较器。 那可能吗? var bob = new object(); MemoryCache.De
我试图弄清楚应该如何使用 MemoryCache 以避免出现内存不足异常。我来自 ASP.Net 背景,缓存管理它自己的内存使用,所以我希望 MemoryCache 会做同样的事情。正如我制作的波纹管
在 Controller 类中,我有 using Microsoft.Extensions.Caching.Memory; private IMemoryCache _cache; private r
Memcached API 有一个 Touch() 方法,它可以更新给定 key 的过期策略。如何使用 .Net ObjectCache 类最好地完成此任务? 我能看到的最好的办法是删除对象并重新添加
当使用 MemoryCache 时,可以设置 AbsoluteExpiration AbsoluteExpirationRelativeToNow 例子: cache.GetOrCreate(
根据 MSDN 文档 here : Do not create MemoryCache instances unless it is required. If you create cache ins
我需要添加缓存功能并找到了一个名为 MemoryCache 的新类。但是,我发现 MemoryCache 有点残缺(我需要区域功能)。除其他事项外,我需要添加类似 ClearAll(region) 的
在我的应用程序中,我使用 MemoryCache,但我不希望项目过期。因此,项目将使用默认策略插入到缓存中,而无需设置 AbsoulteExpiration 或 SlidingExpiration。
MemoryCache类公开了一个名为 .AddOrGetExisting 的方法这是一种线程安全的方法,如果存在则获取,如果不存在则添加。 如果缓存对象不存在,此方法返回 NULL。我想我理解它的值
MemoryCache 是否具有缓存固定数量项目的功能? 例如我们只对从数据库中缓存 2000 个项目感兴趣。在不断向缓存中添加项目的同时,如果超过指定的项目数,则可以删除最旧的项目。 如果不是,我们
我正在使用 .NET 4.0 MemoryCache应用程序中的类并试图限制最大缓存大小,但在我的测试中,缓存似乎并没有真正遵守限制。 我正在使用设置,according to MSDN ,应该限制缓
我将 MemoryCache 与 Sql 依赖项一起使用。我注意到当使用 MemoryCache.Set() 时,如果集合中的某个项目被覆盖,则会发生内存泄漏。考虑以下场景: key=A 的项被插入到
我一直在阅读有关从 .Net Framework 4.0 开始的新 MemoryCache 类的所有地方。根据我的阅读,您可以跨不同的 .Net 应用程序访问 MemoryCache。我正在尝试在 A
我收到这条消息: System.ObjectDisposedException: Cannot access a disposed object. A common cause of this err
应用程序需要加载数据并缓存一段时间。我希望如果应用程序的多个部分想要同时访问同一个缓存键,缓存应该足够智能,只加载一次数据并将该调用的结果返回给所有调用者。然而, MemoryCache 不是这样做的
MemoryCache 是一个线程安全类,根据 this文章。但我不明白它在特定情况下会如何表现。例如我有代码: static private MemoryCache _cache = MemoryC
我不明白在 .NET 4.0 的 System.Runtime.Caching.MemoryCache 中滑动过期应该如何工作。 根据文档,过期时间跨度是“在从缓存中逐出缓存条目之前必须访问缓存条目的
在 .NET 4 MemoryCache 中,有没有办法找到上次访问项目的时间?我确定它在内部被跟踪,因为 CacheItemPolicy 具有 SlidingExpiration 属性。但是我找不到
我正在使用 .NET 4.0 MemoryCache类,我想以线程安全的方式添加或替换缓存中的现有项,但我还想知道我是否替换了现有项或添加了新项。 据我所知,Set方法旨在原子地替换缓存中的项目(如果
我是一名优秀的程序员,十分优秀!