If you only need the cache to return the same value as it was cached, you could serialize the object and deserialize it to get the original values out. The following code is untested, but I've used the idea before for other purposes:
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);
}
}
If you actually want the objects returned to be immutable (meaning changing their value should fail or be no-op) then there's no way to accomplish that generically as you say you want. One option that comes to mind is using an abstract, read-only abstract base class that you store in the cache and create a non-abstract child class that you use when you need the data to be writable.
As suggested by the answers in the question recommended in the comments by Alexei, another option is to implement a write-once class but that on its own is not a small feat and may not provide the flexibility you require.