阻止修改缓存对象



如何从缓存中为对象提供服务,而不用担心使用该对象的代码会更改缓存中的源?

示例:

var instance = new SomeClass();
instance.Text = "Abc";
MemoryCache.Default.Set("Key", instance, new CacheItemPolicy() {  });
instance.Text = "123";
Console.WriteLine((SomeClass)MemoryCache.Default.Get("Key")).Text);
// 123 :(

我希望缓存是不可更改的,可能是通过序列化或其他克隆方法,但我不会担心!

如果只需要缓存返回与缓存时相同的值,则可以序列化对象并反序列化它以获取原始值。以下代码未经测试,但我以前曾将此想法用于其他目的:

using Newtonsoft.Json;
public class CacheObject<T>
{
private string serializedValue;
public CacheObject(T value)
{
// TODO: Add-in serializer settings as needed
this.serializedValue = JsonConvert.SerializeObject(value);
}
public T Value
{
get
{
// TODO: Add-in serializer settings as needed
return JsonConvert.DeserializeObject<T>(this.serializedValue);
}
}
}
public static class CacheExtensions
{
public static void Set<T>(this ObjectCache cache, string key, T value, CacheItemPolicy policy)
{
cache.Set(key, new CacheObject<T>(value), policy);
}
public static T Get<T>(this ObjectCache cache, string key)
{
return (T)(cache.Get(key)?.Value);
}
}

如果你真的希望返回的对象是不可变的(这意味着改变它们的值应该失败或没有操作(,那么就没有办法像你所说的那样实现这一点。脑海中出现的一个选项是使用一个抽象的只读抽象基类,该基类存储在缓存中,并创建一个非抽象的子类,当您需要数据可写时使用。

正如阿列克谢在评论中建议的问题答案所建议的那样,另一种选择是实现一次写入类,但这本身并不是一个小壮举,可能无法提供所需的灵活性。

修改SomeClass,以便在构造函数中私下设置文本,如下所示:

public class SomeClass
{
public string Text { get; private set; }
public SomeClass(string text)
{
Text = text;
}
}

这里有一个可以做到这一点的想法:

使用接口定义缓存行为:

public interface ICache
{
...
void Set(string key, object value, some other parameters);
object Get(string key);
...
}

实现只读(或以某种方式您想要(缓存:

public class ReadOnlyCache : ICache
{
...
void Set(string key, object value, some other parameters)
{
...
// Of cause, the DeepClone() method can be anyone that makes a copy of the instance.
this.cache.Set(key, value.DeepClone(), some other parameters);
...
}
object Get(string key)
{
...
var value = this.cache.Get(key);
// Of cause, the DeepClone() method can be anyone that makes a copy of the instance.
return value.DeepClone();
}
...
}

最新更新