是否有用于缓存数据的通用c#源代码?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了是否有用于缓存数据的通用c#源代码?相关的知识,希望对你有一定的参考价值。

[每次使用数据缓存时,我都必须“发明”几乎相同的样板代码,包括缓存密钥生成,获取(设置)缓存值以及清除缓存。

这通常是这样的:

        ...

        var cache = new Dictionary<string, string>();

        var cacheKey = "some_kind_of_cache_key";
        if (cache.ContainsKey(cacheKey))
        {
            return cache[cacheKey];
        }

        string newCacheValue = MakeSomethingComplicated();

        return cache[cacheKey] = newCacheValue;

我想看看是否有某种可重用的c#源代码用于缓存?

答案

这是我使用的:

public static class MemoryCacheExtensions
{
    public static T GetOrSet<T>(this MemoryCache cache, string cacheKey, Func<T> callbackForSet,
     out bool foundInCache, DateTimeOffset? absoluteExpiration = null)
    {
        foundInCache = true;

        var cacheItem = cache[cacheKey];
        if (cacheItem == null)
        {
            foundInCache = false;

            cacheItem = callbackForSet();

            var absolExpir = absoluteExpiration ?? DateTimeOffset.UtcNow.AddMinutes(5);
            cache.Set(cacheKey, cacheItem, absolExpir); // update or insert
        }

        return (T)cacheItem; // if you're scared of nulls then use: as T
    }   
}

您可以这样称呼它:

public static void Test()
{
    var memCache = new MemoryCache("MyMemCache");
    var cacheKey = "myCacheKey";

    // the first time you call GetOrSet, it will set and return the value
    var cachedValue = memCache.GetOrSet(cacheKey, () =>
    {
        return DateTime.Now;
    }, out bool foundInCache);

    Thread.Sleep(1000);

    // the second time you call GetOrSet, it will return the cached value
    var cachedValue2 = memCache.GetOrSet(cacheKey, () =>
    {
        // this will only be called if the cacheKey was not found
        return DateTime.Now;
    }, out foundInCache);
}

我的默认缓存持续时间是5分钟。您可以通过将第四个参数传递给GetOrSet来更改缓存持续时间

DateTimeOffset.UtcNow.AddMinutes(1); // for caching for 1 min
另一答案

是的,您可以如下创建基类:

public class BaseCache<TValue>
    {
        private readonly IDictionary<string, TValue> hash = new Dictionary<string, TValue>();

        /// <summary>
        /// gets the cache key parts as inputs: f.e. "keyPart1", "keyPart2", "keyPart3"
        /// and turns them into the cache key in the form of "keyPart1_keyPart2_keyPart3"
        /// </summary>
        /// <param name="keyParts"></param>
        /// <returns></returns>
        private string CacheKey(IEnumerable<string> keyParts)
        {
            var keyPartsEnumerated = keyParts as string[] ?? keyParts.ToArray();
            if (!keyPartsEnumerated.Any())
            {
                return String.Empty;
            }

            string retVal = keyPartsEnumerated.Aggregate(string.Empty, (acc, key) => string.IsNullOrEmpty(acc) ? $"{key}" : $"{acc}_{key}");

            return retVal;
        }

        public void SetCacheValue(IEnumerable<string> keyParts, TValue value)
        {
            hash[CacheKey(keyParts)] = value;
        }

        public void SetCacheValue(string key, TValue value)
        {
            SetCacheValue(new[] { key }, value);
        }

        public bool TryGetCacheValue(IEnumerable<string> keyParts, out TValue value)
        {
            var cacheKey = CacheKey(keyParts);
            return hash.TryGetValue(cacheKey, out value);
        }

        public bool TryGetCacheValue(string key, out TValue value)
        {
            return TryGetCacheValue(new[] { key }, out value);
        }

        private string[] GetCacheKeys_WhichStartWith(string startWith)
        {
            return hash.Where(p => p.Key.ToLower().StartsWith(startWith.ToLower())).Select(p => p.Key).ToArray();
        }

        public void ClearCache(string keyStartsWith)
        {
            if (string.IsNullOrEmpty(keyStartsWith))
            {
                return;
            }

            switch (keyStartsWith.ToLower())
            {
                case "all":
                    hash.Clear();
                    return;
                default:
                    var envKeys = GetCacheKeys_WhichStartWith(keyStartsWith);
                    foreach (var envKey in envKeys) hash.Remove(envKey);
                    break;
            }
        }
    }

,并将您的专用缓存导出为单例:

public sealed class ExampleCache : BaseCache<bool?>
    {
        private static readonly Lazy<ExampleCache> instance = new Lazy<ExampleCache>(() => new ExampleCache());
        public static ExampleCache Instance => instance.Value;

        private ExampleCache() { }
    }

请参考到https://github.com/yugklim/CacheAsSingletonDemo.git

以上是关于是否有用于缓存数据的通用c#源代码?的主要内容,如果未能解决你的问题,请参考以下文章

Swift新async/await并发中利用Task防止指定代码片段执行的数据竞争(Data Race)问题

Swift新async/await并发中利用Task防止指定代码片段执行的数据竞争(Data Race)问题

是否有可用于我正在构建的应用程序的现有数据层?

通用方法总是返回NULL [关闭]

架构丰富的代码片段也应该用于产品列表吗?

c_cpp 快速代码片段,用于在统计(阻止)/ dev / rdsk中的设备时验证fstat64和stat64的行为。