我正在寻找一种为任何对象提供通用本地缓存的方法。这是代码:
private static readonly Dictionary<Type,Dictionary<string,object>> _cache
= new Dictionary<Type, Dictionary<string, object>>();
//The generic parameter allow null values to be cached
private static void AddToCache<T>(string key, T value)
{
if(!_cache.ContainsKey(typeof(T)))
_cache.Add(typeof(T),new Dictionary<string, object>());
_cache[typeof (T)][key] = value;
}
private static T GetFromCache<T>(string key)
{
return (T)_cache[typeof (T)][key];
}
1-有没有办法不使用getfromcache方法?
2-有没有办法确保第二个字典中的类型安全,假设所有对象都具有相同的类型。 (这是由addToCache方法提供的,但我更喜欢设计中的类型控件)。例如,要具有以下类型的_cache
Dictionary<Type,Dictionary<string,typeof(type)>>
THX
答案 0 :(得分:12)
试试这个:
static class Helper<T>
{
internal static readonly Dictionary<string, T> cache = new Dictionary<string, T>();
}
private static void AddToCache<T>(string key, T value)
{
Helper<T>.cache[key] = value;
}
private static T GetFromCache<T>(string key)
{
return Helper<T>.cache[key];
}
答案 1 :(得分:3)
为什么不将泛型参数放到类声明中:
public class Cache<T>
{
private Dictionary<string, T> _cache = new Dictionary<string, T>();
...
}
如果您愿意,可以是静态的
答案 2 :(得分:1)
除非原始类型没有装箱,否则你不会获得太多收益。
private static readonly Dictionary<Type,Dictionary<string,object>> _cache
= new Dictionary<Type, IDictionary>();
//The generic parameter allow null values to be cached
private static void AddToCache<T>(string key, T value)
{
// create a dictionary of the correct type
if(!_cache.ContainsKey(typeof(T)))
_cache.Add(typeof(T),new Dictionary<string, T>());
_cache[typeof (T)][key] = value;
}
private static T GetFromCache<T>(string key)
{
// casting the dictionary instead of the value
Dictionary<string, T> typedDictionary = (Dictionary<string, T>)_cache[typeof (T)];
return typedDictionary[key];
}
当然需要更多未找到处理。
答案 3 :(得分:1)
自举:
services.AddMemoryCache();
用法:
public class HomeController : Controller
{
private IMemoryCache _cache;
public HomeController(IMemoryCache memoryCache)
{
_cache = memoryCache;
var onlineAt = _cache.Get<DateTime?>("self:startup");
}
有关写入和引导详细信息,请查看上面的链接。它结合了我的答案所包含的大部分内容。您还可以使用Microsoft.Extensions.Caching.Redis
或其他分布式缓存。
这是现在的'官方'方法。
后代的原始答案
我必须把它扔出去,这看起来不像你应该做的事情。通过使用依赖注入/控制反转库,Enterprise Library CacheManager之类的工具或使用分布式内存缓存程序(如Memcache或Microsoft Velocity),无论您做什么都可能更好。
答案 4 :(得分:0)
如果在编译时不知道所需的类型,则无法创建强类型的缓存。如果你在运行时之前不知道所需的类型,那么问题的答案是否定的,我很害怕。
答案 5 :(得分:0)
应该放入几个锁,也许还有几个克隆......但这应该可以。
class Program
{
static void Main(string[] args)
{
CacheObject<int>.Instance["hello"] = 5;
CacheObject<int>.Instance["hello2"] = 6;
CacheObject<string>.Instance["hello2"] = "hi";
Console.WriteLine(CacheObject<string>.Instance["hello2"]); //returns hi
}
}
public class CacheObject<V> : CacheObject<string, V> { }
public class CacheObject<K,V>
{
private static CacheObject<K, V> _instance = new CacheObject<K, V>();
public static CacheObject<K, V> Instance { get { return _instance; } }
private Dictionary<K, V> _store = new Dictionary<K, V>();
public T this[K index]
{
get { return _store.ContainsKey(index) ? _store[index] : default(V); }
set
{
if (_store.ContainsKey(index)) _store.Remove(index);
if (value != null) _store.Add(index, value);
}
}
}
答案 6 :(得分:0)
即使这是一个较旧的线程,它也会在我今天运行的搜索中弹出...这是@Daniel帖子的更新版本,它实现了线程安全(如多个良好注释中所述)以及自我-填充/惰性缓存初始化:
public static class SimpleLazyCacheHelper<T>
{
private static readonly ConcurrentDictionary<string, Lazy<T>> cache = new ConcurrentDictionary<string, Lazy<T>>();
[Obsolete("This method adds existing values to the cache, but it's best to use GetOrAddToCache() to facilitate a self-populating cache (especially in a Web environment)")]
public static void AddToCache(string key, T value)
{
cache.TryAdd(key, new Lazy<T>(() => value));
}
[Obsolete("This method returns only existing values; it's best to initialize cache values via GetOrAddToCache()")]
public static T GetFromCache(string key)
{
return cache[key].Value;
}
/// <summary>
/// Provides a self-populating/blocking approach to the cache so that ALL Threads wait for the first thread that requested a cache key
/// to be initialized and populated into the cache. This means that they will always wait less time than if they did all the
/// work itself. Very useful for long running work (e.g. DB calls, I/O processing, etc).
/// More info. on the value fo self-populating approach is here:
/// https://www.ehcache.org/documentation/2.8/apis/constructs.html
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key"></param>
/// <param name="valueFactory"></param>
public static T GetOrAddToCache(string key, Func<T> valueFactory)
{
return cache.GetOrAdd(key, new Lazy<T>(valueFactory)).Value;
}
}
用法是:
CacheHelper<MyCacheableClass>.GetOrAddToCache($"UniqueDynamicKey", () =>
{
//
//... do some long running work...
//
return new MyCacheableClass();
});
这里也是要点:https://gist.github.com/cajuncoding/e2ff490d79812c83bedfd5a77888e727
对于任何正在寻找我们在生产中使用的充实解决方案的人,您可以在我的LazyCachHelpers项目中看到相同的模式: https://github.com/cajuncoding/LazyCacheHelpers