防止修改缓存对象

时间:2021-04-22 19:05:41

标签: c# in-memory memorycache

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

示例:

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 :(

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

3 个答案:

答案 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();
    }
    ...
}