C# MemoryCache學習筆記

    不少狀況下須要用到緩存,合理利用緩存一方面能夠提升程序的響應速度,同時能夠減小對特定資源訪問的壓力。爲了不每次請求都去訪問後臺的html

資源(例如數據庫),通常會考慮將一些更新不是很頻繁的、能夠重用的數據,經過必定的方式臨時地保存起來,後續的請求根據狀況能夠直接訪問這數據庫

些保存起來的數據,這種機制就是所謂的緩存機制。緩存

    .NET 4.0的緩存功能主要由三部分組成:System.Runtime.Caching,System.Web.Caching.Cache和Output Cache。app

    MemoryCache:這個是在.NET 4.0中新增的緩存框架,Namespace:System.Runtime.Caching ,Assembly:System.Runtime.Caching.dll。框架

    System.Web.Caching.Cache:這個是在.NET 2.0開始就一直存在的緩存對象,通常主要用在Web中,固然也能夠用於Winform裏面,不過要引用ide

System.Web.dll。ui

    Output Cache:這個是在Asp.NET裏面使用的。在ASP.NET 4.0以前,都是直接使用System.Web.Caching.Cache來緩存HTML片斷。在ASP.NET 4.0spa

中對它進行了從新設計,提供了一個OutputCacheProvider供開發人員進行擴展,可是它默認狀況下,仍然使用System.Web.Caching.Cache來作作緩存。設計

    下面演示MemoryCache的簡單使用:code

    一、添加一個類,命名爲ConfigHelper,代碼以下:

    /// <summary>
    /// 配置幫助類
    /// </summary>
    class ConfigHelper
    {
        /// <summary>
        /// 獲取管理配置文件對象
        /// </summary>
        /// <param name="configPath">指定要管理的配置文件路徑,若是爲空或不存在,則爲管理程序集默認的配置文件路徑。</param>
        /// <returns></returns>
        private static Configuration GetConfiguration(string configPath = null)
        {
            if (!string.IsNullOrEmpty(configPath) && File.Exists(configPath))
            {
                ExeConfigurationFileMap map = new ExeConfigurationFileMap
                {
                    ExeConfigFilename = configPath
                };
                return ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
            }
            else
            {
                return ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
            }
        }

        /// <summary>
        /// 獲取指定配置文件+配置名稱的配置項的值
        /// </summary>
        public static string GetAppSettingValue(string key, string defaultValue = null, string configPath = null)
        {
            var config = GetConfiguration(configPath);
            var appSetting = config.AppSettings.Settings[key];
            return appSetting.Value;
        }

        /// <summary>
        /// 獲取全部配置值
        /// </summary>
        public static Dictionary<string, string> GetAppSettingValues(string configPath = null)
        {
            Dictionary<string, string> settingDic = new Dictionary<string, string>();
            var config = GetConfiguration(configPath);
            var settings = config.AppSettings.Settings;
            foreach (string key in settings.AllKeys)
            {
                settingDic[key] = settings[key].ToString();
            }
            return settingDic;
        }

        /// <summary>
        /// 設置配置值(存在則更新,不存在則新增。)
        /// </summary>
        public static void SetAppSettingValue(string key, string value, string configPath = null)
        {
            var config = GetConfiguration(configPath);
            var setting = config.AppSettings.Settings[key];
            if (setting == null)
            {
                config.AppSettings.Settings.Add(key, value);
            }
            else
            {
                setting.Value = value;
            }

            config.Save(ConfigurationSaveMode.Modified);
            ConfigurationManager.RefreshSection("appSettings");
        }

        /// <summary>
        /// 設置多個配置值(存在則更新,不存在則新增)
        /// </summary>
        public static void SetAppSettingValues(IEnumerable<KeyValuePair<string, string>> settingValues, string configPath = null)
        {
            var config = GetConfiguration(configPath);
            foreach (var item in settingValues)
            {
                var setting = config.AppSettings.Settings[item.Key];
                if (setting == null)
                {
                    config.AppSettings.Settings.Add(item.Key, item.Value);
                }
                else
                {
                    setting.Value = item.Value;
                }
            }
            config.Save(ConfigurationSaveMode.Modified);
            ConfigurationManager.RefreshSection("appSettings");
        }

        /// <summary>
        /// 刪除配置值
        /// </summary>
        public static void RemoveAppSetting(string key, string configPath = null)
        {
            var config = GetConfiguration(configPath);
            config.AppSettings.Settings.Remove(key);
            config.Save(ConfigurationSaveMode.Modified);
            ConfigurationManager.RefreshSection("appSettings");
        }

        /// <summary>
        /// 刪除多個配置值
        /// </summary>
        public static void RemoveAppSettings(string configPath = null, params string[] keys)
        {
            var config = GetConfiguration(configPath);
            if (keys != null)
            {
                foreach (string key in keys)
                {
                    config.AppSettings.Settings.Remove(key);
                }
            }
            else
            {
                config.AppSettings.Settings.Clear();
            }
            config.Save(ConfigurationSaveMode.Modified);
            ConfigurationManager.RefreshSection("appSettings");
        }

        /// <summary>
        /// 獲取鏈接字符串
        /// </summary>
        public static string GetConnectionString(string name, string defaultconnString = null, string configPath = null)
        {
            var config = GetConfiguration(configPath);
            var connStringSettings = config.ConnectionStrings.ConnectionStrings[name];
            if (connStringSettings == null)
            {
                return defaultconnString;
            }
            return connStringSettings.ConnectionString;
        }

        /// <summary>
        /// 獲取指定配置文件+鏈接名稱的鏈接字符串配置項
        /// </summary>
        public static ConnectionStringSettings GetConnectionStringSetting(string name, string configPath = null)
        {
            var config = GetConfiguration(configPath);
            var connStringSettings = config.ConnectionStrings.ConnectionStrings[name];
            return connStringSettings;
        }

        /// <summary>
        /// 獲取全部的鏈接字符串配置項
        /// </summary>
        public static Dictionary<string, ConnectionStringSettings> GetConnectionStringSettings(string configPath = null)
        {
            var config = GetConfiguration(configPath);
            var connStringSettingDic = new Dictionary<string, ConnectionStringSettings>();
            var connStringSettings = ConfigurationManager.ConnectionStrings;
            foreach (ConnectionStringSettings item in connStringSettings)
            {
                connStringSettingDic[item.Name] = item;
            }
            return connStringSettingDic;
        }

        /// <summary>
        /// 設置鏈接字符串的值(存在則更新,不存在則新增。)
        /// </summary>
        public static void SetConnectionString(string name, string connString, string provider, string configPath = null)
        {
            var config = GetConfiguration(configPath);
            ConnectionStringSettings connStringSettings = config.ConnectionStrings.ConnectionStrings[name];
            if (connStringSettings != null)
            {
                connStringSettings.ConnectionString = connString;
                connStringSettings.ProviderName = provider;
            }
            else
            {
                connStringSettings = new ConnectionStringSettings(name, connString, provider);
                config.ConnectionStrings.ConnectionStrings.Add(connStringSettings);
            }

            config.Save(ConfigurationSaveMode.Modified);
            ConfigurationManager.RefreshSection("connectionStrings");
        }

        /// <summary>
        /// 設置多個鏈接字符串的值(存在則更新,不存在則新增。)
        /// </summary>
        public static void SetConnectionStrings(IEnumerable<ConnectionStringSettings> connStringSettings, string configPath = null)
        {
            var config = GetConfiguration(configPath);
            foreach (var item in connStringSettings)
            {
                ConnectionStringSettings connStringSetting = config.ConnectionStrings.ConnectionStrings[item.Name];
                if (connStringSetting != null)
                {
                    connStringSetting.ConnectionString = item.ConnectionString;
                    connStringSetting.ProviderName = item.ProviderName;
                }
                else
                {
                    config.ConnectionStrings.ConnectionStrings.Add(item);
                }
            }

            config.Save(ConfigurationSaveMode.Modified);
            ConfigurationManager.RefreshSection("connectionStrings");
        }

        /// <summary>
        /// 刪除鏈接字符串配置項
        /// </summary>
        public static void RemoveConnectionString(string name, string configPath = null)
        {
            var config = GetConfiguration(configPath);
            config.ConnectionStrings.ConnectionStrings.Remove(name);
            config.Save(ConfigurationSaveMode.Modified);
            ConfigurationManager.RefreshSection("connectionStrings");
        }

        /// <summary>
        /// 刪除多個鏈接字符串配置項
        /// </summary>
        public static void RemoveConnectionStrings(string configPath = null, params string[] names)
        {
            var config = GetConfiguration(configPath);
            if (names != null)
            {
                foreach (string name in names)
                {
                    config.ConnectionStrings.ConnectionStrings.Remove(name);
                }
            }
            else
            {
                config.ConnectionStrings.ConnectionStrings.Clear();
            }
            config.Save(ConfigurationSaveMode.Modified);
            ConfigurationManager.RefreshSection("connectionStrings");
        }
    }
View Code

    二、添加一個類,命名爲MemoryCacheHelper(注意需引用System.Runtime.Caching.dll),代碼以下:

    /// <summary>
    /// 內存緩存幫助類,支持絕對過時時間、滑動過時時間、文件依賴三種緩存方式。
    /// </summary>
    class MemoryCacheHelper
    {
        private static readonly object _locker1 = new object(), _locker2 = new object();

        /// <summary>
        /// 取緩存項,若是不存在則返回空。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public static T GetCacheItem<T>(string key)
        {
            try
            {
                return (T)MemoryCache.Default[key];
            }
            catch
            {
                return default(T);
            }
        }

        /// <summary>
        /// 是否包含指定鍵的緩存項
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static bool Contains(string key)
        {
            return MemoryCache.Default.Contains(key);
        }

        /// <summary>
        /// 取緩存項,若是不存在則新增緩存項。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="cachePopulate"></param>
        /// <param name="slidingExpiration"></param>
        /// <param name="absoluteExpiration"></param>
        /// <returns></returns>
        public static T GetOrAddCacheItem<T>(string key, Func<T> cachePopulate, TimeSpan? slidingExpiration = null, DateTime? absoluteExpiration = null)
        {
            if (string.IsNullOrWhiteSpace(key)) throw new ArgumentException("Invalid cache key");
            if (cachePopulate == null) throw new ArgumentNullException("cachePopulate");
            if (slidingExpiration == null && absoluteExpiration == null) throw new ArgumentException("Either a sliding expiration or absolute must be provided");

            if (MemoryCache.Default[key] == null)
            {
                lock (_locker1)
                {
                    if (MemoryCache.Default[key] == null)
                    {
                        T cacheValue = cachePopulate();
                        if (!typeof(T).IsValueType && cacheValue == null)   //若是是引用類型且爲NULL則不存緩存
                        {
                            return cacheValue;
                        }

                        var item = new CacheItem(key, cacheValue);
                        var policy = CreatePolicy(slidingExpiration, absoluteExpiration);

                        MemoryCache.Default.Add(item, policy);
                    }
                }
            }

            return (T)MemoryCache.Default[key];
        }

        /// <summary>
        /// 取緩存項,若是不存在則新增緩存項。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="cachePopulate"></param>
        /// <param name="dependencyFilePath"></param>
        /// <returns></returns>
        public static T GetOrAddCacheItem<T>(string key, Func<T> cachePopulate, string dependencyFilePath)
        {
            if (string.IsNullOrWhiteSpace(key)) throw new ArgumentException("Invalid cache key");
            if (cachePopulate == null) throw new ArgumentNullException("cachePopulate");

            if (MemoryCache.Default[key] == null)
            {
                lock (_locker2)
                {
                    if (MemoryCache.Default[key] == null)
                    {
                        T cacheValue = cachePopulate();
                        if (!typeof(T).IsValueType && cacheValue == null)   //若是是引用類型且爲NULL則不存緩存
                        {
                            return cacheValue;
                        }

                        var item = new CacheItem(key, cacheValue);
                        var policy = CreatePolicy(dependencyFilePath);

                        MemoryCache.Default.Add(item, policy);
                    }
                }
            }

            return (T)MemoryCache.Default[key];
        }

        /// <summary>
        /// 指定緩存項的一組逐出和過時詳細信息
        /// </summary>
        /// <param name="slidingExpiration"></param>
        /// <param name="absoluteExpiration"></param>
        /// <returns></returns>
        private static CacheItemPolicy CreatePolicy(TimeSpan? slidingExpiration, DateTime? absoluteExpiration)
        {
            var policy = new CacheItemPolicy();

            if (absoluteExpiration.HasValue)
            {
                policy.AbsoluteExpiration = absoluteExpiration.Value;
            }
            else if (slidingExpiration.HasValue)
            {
                policy.SlidingExpiration = slidingExpiration.Value;
            }

            policy.Priority = CacheItemPriority.Default;

            return policy;
        }

        /// <summary>
        /// 指定緩存項的一組逐出和過時詳細信息
        /// </summary>
        /// <param name="filePath"></param>
        /// <returns></returns>
        private static CacheItemPolicy CreatePolicy(string filePath)
        {
            CacheItemPolicy policy = new CacheItemPolicy();
            policy.ChangeMonitors.Add(new HostFileChangeMonitor(new List<string>() { filePath }));
            policy.Priority = CacheItemPriority.Default;
            return policy;
        }

        /// <summary>
        /// 移除指定鍵的緩存項
        /// </summary>
        /// <param name="key"></param>
        public static void RemoveCacheItem(string key)
        {
            if (Contains(key))
            {
                MemoryCache.Default.Remove(key);
            }
        }
    }
View Code

    三、添加一個WinForm窗體,命名爲Main,並添加一個按鈕。

    四、配置App.config:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <startup> 
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
  </startup>
  <connectionStrings>
    <add name ="connString" connectionString="server=.;database=db_test;uid=sa;pwd=********;" />
  </connectionStrings>
</configuration>

    五、Main窗體代碼以下:

        private void button1_Click(object sender, EventArgs e)
        {
            int times1 = 0, times2 = 0;
            for (int i = 0; i < 10; i++)
            {
                if (MemoryCacheHelper.Contains("connString"))
                {
                    times1++;
                }
                else
                {
                    times2++;
                    string connstr = MemoryCacheHelper.GetOrAddCacheItem("connString", () =>
                    {
                        return ConfigHelper.GetConnectionString("connString", null);
                    }, Application.StartupPath + @"\App.config");
                }
            }
            MessageBox.Show($"內存緩存讀取次數:{times1},非內存緩存讀取次數:{times2}", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

    六、運行結果以下:

    參考自:

    http://www.javashuo.com/article/p-burxssup-mz.html

    https://www.cnblogs.com/zuowj/p/8366735.html

    https://www.cnblogs.com/zuowj/p/8440902.html

相關文章
相關標籤/搜索