如何从缓存中提供对象,而不必担心使用该对象的代码会更改缓存中的源?
示例:
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 :(
我希望缓存是不可更改的,可能是通过序列化或其他克隆方法,但我不会担心!
答案 0 :(得分:1)
如果您只需要缓存返回与缓存相同的值,您可以序列化对象并反序列化它以获取原始值。以下代码未经测试,但我之前曾将这个想法用于其他目的:
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);
}
}
如果您确实希望返回的对象是不可变的(意味着更改它们的值应该失败或无操作),那么就无法像您所说的那样一般地完成该操作。想到的一种选择是使用您存储在缓存中的抽象只读抽象基类,并创建一个非抽象子类,当您需要数据可写时使用该类。
正如 Alexei 在评论中推荐的问题中的答案所建议的那样,另一种选择是实现一个一次性编写的类,但这本身并不是一件小事,可能无法提供您所需的灵活性。
答案 1 :(得分:0)
修改 SomeClass 以便在构造函数中私下设置文本,如下所示:
public class SomeClass
{
public string Text { get; private set; }
public SomeClass(string text)
{
Text = text;
}
}
答案 2 :(得分:0)
以下是您可以执行此操作的想法:
使用接口定义缓存行为:
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();
}
...
}