Winform里面的缓存,MemoryCache使用
缓存在很多情况下需要用到,合理利用缓存可以一方面可以提高程序的响应速度,同时可以减少对特定资源访问的压力。本文主要针对自己在Winform方面的缓存使用做一个引导性的介绍,希望大家能够从中了解一些缓存的使用场景和使用方法。缓存是一个中大型系统所必须考虑的问题。为了避免每次请求都去访问后台的资源(例如数据库),我们一般会考虑将一些更新不是很频繁的,可以重用的数据,通过一定的方式临时地保存起来,后续的请求根据情况可以直接访问这些保存起来的数据。这种机制就是所谓的缓存机制。
.NET 4.0的缓存功能主要由三部分组成:System.Runtime.Caching,System.Web.Caching.Cache和Output Cache。
MemoryCache对象:这是在.NET 4.0中新增的缓存框架,在Namespace:System.Runtime.Caching ,Assembly:System.Runtime.Caching.dll中。
System.Web.Caching.Cache这个则是在.NET2.0开始就一直存在的缓存对象,一般主要用在Web中,当然也可以用于Winform里面,不过要引用System.Web.dll。
Output Cache则是Asp.NET里面使用的,在ASP.NET 4.0之前的版本都是直接使用System.Web.Caching.Cache来缓存HTML片段。在ASP.NET 4.0中对它进行了重新设计,提供了一个OutputCacheProvider供开发人员进行扩展,但是它默认情况下,仍然使用System.Web.Caching.Cache来做做缓存。
1、自定义Hastable的缓存处理。
除了上面三种的缓存机制,一般我们还可以在静态对象里面通过HashTable或者Dictionary的方式进行自定义的缓存存储和使用。
例如我在我自己所开发的程序里面,都使用了工厂类来创建业务对象,由于创建业务对象以及数据访问层对象,是一个在界面或者中间层反复调用的操作,因此需要把经常调用的对象把它存储起来,下载调用的时候,直接从内存中取出来即可。如下面的BLLFactory类,就是一个基于泛型对象的业务类的创建操作,使用了基于Hashtable的静态对象进行缓存处理。

/// <summary>
/// 对业务类进行构造的工厂类
/// </summary>
/// <typeparam name="T">业务对象类型</typeparam>
public class BLLFactory<T> where T : class
{
private static Hashtable objCache = new Hashtable();
private static object syncRoot = new Object(); /// <summary>
/// 创建或者从缓存中获取对应业务类的实例
/// </summary>
public static T Instance
{
get
{
string CacheKey = typeof(T).FullName;
T bll = (T)objCache[CacheKey]; //从缓存读取
if (bll == null)
{
lock (syncRoot)
{
if (bll == null)
{
bll = Reflect<T>.Create(typeof(T).FullName, typeof(T).Assembly.GetName().Name); //反射创建,并缓存
objCache.Add(typeof(T).FullName, bll);
}
}
}
return bll;
}
}
}

2、使用.NET4.0的MemoryCache对象实现缓存
MemoryCache的使用网上介绍的不多,不过这个是.NET4.0新引入的缓存对象,估计主要是替换原来企业库的缓存模块,使得.NET的缓存可以无处不在,而不用基于特定的Windows版本上使用。
首先我们使用来创建一个基于MemoryCache的辅助类MemoryCacheHelper,方便调用进行缓存处理。

/// <summary>
/// 基于MemoryCache的缓存辅助类
/// </summary>
public static class MemoryCacheHelper
{
private static readonly Object _locker = new object(); public static T GetCacheItem<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(_locker)
{
if(MemoryCache.Default[key] == null)
{
var item = new CacheItem(key, cachePopulate());
var policy = CreatePolicy(slidingExpiration, absoluteExpiration); MemoryCache.Default.Add(item, policy);
}
}
} return (T)MemoryCache.Default[key];
} 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>
/// 基于System.Runtime.Caching.dll中的MemoryCache的缓存辅助类
/// </summary>
public static class MemoryCacheHelper
{ private static readonly Object _locker = new object(); /// <summary>
/// 如果缓存中存在指定的key,则优先从缓存中返回
/// </summary>
/// <typeparam name="T">返回值类型</typeparam>
/// <param name="key">缓存关键字</param>
/// <param name="cachePopulate">需要执行的方法、Lambda表达式、(匿名)代理等。
/// <code>例如:() => "测试", 或者
/// delegate () { return new aaa("测试"); },
/// </code>
/// </param>
/// <param name="slidingExpiration">滑动窗口模式的使用过期时间</param>
/// <param name="absoluteExpiration">绝对过期时间</param>
/// <returns></returns>
public static T GetCacheItem<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 (_locker)
{
if (MemoryCache.Default[key] == null)
{
var item = new CacheItem(key, cachePopulate());
var policy = CreatePolicy(slidingExpiration, absoluteExpiration); MemoryCache.Default.Add(item, policy);
}
}
} return (T)((MemoryCache.Default[key] is T) ? MemoryCache.Default[key] : default(T));
//return (T)MemoryCache.Default[key];
} /// <summary>
/// 如果缓存中存在指定的key,则优先从缓存中返回
/// </summary>
/// <typeparam name="T">返回值类型</typeparam>
/// <param name="key">缓存关键字</param>
/// <param name="cachePopulate">需要执行的方法、Lambda表达式、(匿名)代理等。
/// <code>例如:() => "测试", 或者
/// delegate () { return new aaa("测试"); },
/// </code>
/// </param>
/// <param name="expirationTime">缓存过期时间</param>
/// <param name="expirationTimeType">缓存过期时间类型</param>
/// <param name="enabledCache">是否启用缓存,如果false则每次都是直接执行被调方法cachePopulate,默认启用,</param>
/// <returns></returns>
public static T GetCacheItem<T>(String key, Func<T> cachePopulate, TimeSpan expirationTime, ExpirationTimeType expirationTimeType, bool enabledCache = true)
{
if (String.IsNullOrWhiteSpace(key)) throw new ArgumentException("Invalid cache key");
if (cachePopulate == null) throw new ArgumentNullException("cachePopulate");
if (expirationTime == null) throw new ArgumentException("Either a sliding expiration must be provided"); T tmp = default(T); if (enabledCache)
{
if (MemoryCache.Default[key] == null)
{
lock (_locker)
{
if (MemoryCache.Default[key] == null)
{
Console.WriteLine("MemoryCache is null.");
CacheItem item = new CacheItem(key, cachePopulate()); CacheItemPolicy policy = null;
if (expirationTimeType == ExpirationTimeType.AbsoluteExpirationTimeType)
policy = CreatePolicy(null, DateTime.Now.Add(expirationTime));
else if (expirationTimeType == ExpirationTimeType.SlidingExpirationTimeType)
policy = CreatePolicy(expirationTime, null);
else
policy = CreatePolicy(TimeSpan.Zero, null); MemoryCache.Default.Add(item, policy);
}
}
}
tmp = (MemoryCache.Default[key] is T) ? (T)MemoryCache.Default[key] : default(T);
//return (MemoryCache.Default[key] is T) ? (T)MemoryCache.Default[key] : default(T);
//return (T)MemoryCache.Default[key];
}
else
{
tmp = cachePopulate();
} return tmp;
} /// <summary>
/// 从缓存中移除知道键值的缓存对象
/// </summary>
/// <param name="key">缓存对象的键</param>
/// <returns></returns>
public static bool RemoveCacheItem(string key)
{
bool isRemove = false;
try
{
if (MemoryCache.Default[key] != null)
{
lock (_locker)
{
if (MemoryCache.Default[key] != null)
{
MemoryCache.Default.Remove(key);
}
}
}
isRemove = true;
}
catch (Exception ex)
{
throw ex;
} return isRemove;
} /// <summary>
/// 构造缓存过期时间和优先级
/// </summary>
/// <param name="slidingExpiration">滑动窗口模式的使用过期时间</param>
/// <param name="absoluteExpiration">绝对过期时间</param>
/// <returns></returns>
private static CacheItemPolicy CreatePolicy(TimeSpan? slidingExpiration, DateTime? absoluteExpiration)
{
if (slidingExpiration == null && absoluteExpiration == null)
throw new ArgumentException("Either a sliding expiration or absolute must be provided"); CacheItemPolicy policy = new CacheItemPolicy(); if (slidingExpiration.HasValue)
{
policy.SlidingExpiration = slidingExpiration.Value;
}
else if (absoluteExpiration.HasValue)
{
policy.AbsoluteExpiration = absoluteExpiration.Value;
}
policy.Priority = CacheItemPriority.Default; //List<string> filePaths = new List<string>();
//filePaths.Add("c:\\cache\\example.txt");
//policy.ChangeMonitors.Add(new HostFileChangeMonitor(filePaths)); return policy;
} /// <summary>
/// 缓存过期时间类型
/// </summary>
public enum ExpirationTimeType
{
/// <summary>
/// 滑动窗口模式的使用过期时间
/// </summary>
SlidingExpirationTimeType = , /// <summary>
/// 绝对过期时间
/// </summary>
AbsoluteExpirationTimeType =
} }
这个辅助类只有一个public方法,就是GetCacheItem,使用的时候,需要指定key和获取数据的处理代理,还有缓存的过期时间,是基于TimeSpan的还是基于绝对时间的,选择其一。
上面的辅助类,我们在什么情况下会使用到呢?
假如在一个工作流模块中用到了人员ID,而人员ID需要进行人员名称的转义,人员信息我们一般知道放在权限系统模块里面,那么如果在工作流里面需要频繁对人员ID进行转义,那么就需要方法调用权限系统的接口模块,这样处理就可以使用缓存模块进行优化处理的了。

void gridView1_CustomColumnDisplayText(object sender, DevExpress.XtraGrid.Views.Base.CustomColumnDisplayTextEventArgs e)
{
if (e.Column.FieldName.Equals("ProcUser") || e.Column.FieldName.Equals("ProcUid") || e.Column.FieldName.Equals("UserId"))
{
if (e.Value != null)
{
e.DisplayText = SecurityHelper.GetUserFullName(e.Value.ToString());
}
}
}

其中的SecurityHelper.GetUserFullName是我对调用进行基于缓存的二次封装,具体逻辑如下所示。

/// <summary>
/// 根据用户的ID,获取用户的全名,并放到缓存里面
/// </summary>
/// <param name="userId">用户的ID</param>
/// <returns></returns>
public static string GetUserFullName(string userId)
{
string key = "Security_UserFullName" + userId;
string fullName = MemoryCacheHelper.GetCacheItem<string>(key,
delegate() { return BLLFactory<User>.Instance.GetFullNameByID(userId.ToInt32()); },
new TimeSpan(, , ));//30分钟过期
return fullName;
}

MemoryCacheHelper的方法GetCacheItem里面的Func<T>我使用了一个匿名函数用来获取缓存的值。
delegate() { return BLLFactory<User>.Instance.GetFullNameByID(userId.ToInt32()); }
而调用BLLFactory<User>.Instance.GetFullNameByID则是从数据库里面获取对应的数据了。
这样在第一次或者缓存过期的时候,自动调用业务对象类的方法来获取数据了。
最后,在界面上调用GetUserFullName的方法即可实现基于缓存方式的调用,程序第一次使用的,碰到指定的键没有数据,就去数据库里面获取,以后碰到该键,则直接获取缓存的数据了。
下面图形是程序具体的实现效果。
当然,以上两种方式都还可以通过AOP的注入方式实现代码的简化操作,不过由于对AOP的引入,会涉及到更多的知识点,而且熟悉程序还不够,所以依然采用较为常用的方式来处理缓存的数据。
出处:https://www.cnblogs.com/wuhuacong/p/3526335.html
======================================================================================
摘要
在对winform做的项目优化的时候,首先想到的是对查询,并不经常变化的数据进行缓存,但对web项目来说有System.Web.Caching.Cache类进行缓存,那么winform端该如何呢?你可能会想到,存到文件中,但那可能有问题,文件操作权限问题,IO操作性能问题。
解决办法
针对exe的项目,可以使用MemoryCache这个类,进行内存级别的缓存。
辅助类

/// <summary>
/// 基于MemoryCache的缓存辅助类
/// </summary>
public static class MemoryCacheHelper
{
private static readonly Object _locker = new object(); public static T FindCacheItem<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 (_locker)
{
if (MemoryCache.Default[key] == null)
{
var item = new CacheItem(key, cachePopulate());
var policy = CreatePolicy(slidingExpiration, absoluteExpiration); MemoryCache.Default.Add(item, policy);
}
}
} return (T)MemoryCache.Default[key];
}
/// <summary>
/// 移除缓存
/// </summary>
/// <param name="key"></param>
public static void RemoveCache(string key)
{
MemoryCache.Default.Remove(key);
}
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;
}
}

测试

class Program
{
static void Main(string[] args)
{
string cacheKey = "person_key";
Person p = MemoryCacheHelper.FindCacheItem<Person>(cacheKey,
() =>
{
return new Person() { Id = Guid.NewGuid(), Name = "wolfy" };
}, new TimeSpan(, , ));
if (p != null)
{
Console.WriteLine(p.ToString());
}
Console.WriteLine("获取缓存中数据");
Person p2 = MemoryCacheHelper.FindCacheItem<Person>(cacheKey,
() =>
{
return new Person() { Id = Guid.NewGuid(), Name = "wolfy" };
}, new TimeSpan(, , ));
if (p2 != null)
{
Console.WriteLine(p2.ToString());
}
MemoryCacheHelper.RemoveCache(cacheKey);
Person p3 = MemoryCacheHelper.FindCacheItem<Person>(cacheKey,
() =>
{
return new Person() { Id = Guid.NewGuid(), Name = "wolfy" };
}, new TimeSpan(, , ));
if (p3 != null)
{
Console.WriteLine(p3.ToString());
}
Console.Read();
} }
public class Person
{
public Guid Id { set; get; }
public string Name { set; get; }
public override string ToString()
{
return Id.ToString() + "\t" + Name;
}
}

参考:
https://msdn.microsoft.com/en-us/library/system.runtime.caching.memorycache(v=vs.110).aspx
出处:https://www.cnblogs.com/wolf-sun/p/7251343.html
Winform里面的缓存,MemoryCache使用的更多相关文章
- Winform里面的缓存使用
缓存在很多情况下需要用到,合理利用缓存可以一方面可以提高程序的响应速度,同时可以减少对特定资源访问的压力.本文主要针对自己在Winform方面的缓存使用做一个引导性的介绍,希望大家能够从中了解一些缓存 ...
- 详解Winform里面的缓存使用
缓存在很多情况下需要用到,合理利用缓存可以一方面可以提高程序的响应速度,同时可以减少对特定资源访问的压力.本文主要针对自己在Winform方面的缓存使用做一个引导性的介绍,希望大家能够从中了解一些缓存 ...
- NET下三种缓存机制(Winform里面的缓存使用 )
原文(http://www.cnblogs.com/wuhuacong/p/3526335.html)非常感谢伍华聪作者的分享! 缓存在很多情况下需要用到,合理利用缓存可以一方面可以提高程序的响应速度 ...
- winform中使用缓存
文章:Winform里面的缓存使用 另外一篇文章:缓存-MemoryCache Class
- Asp.net Core 缓存 MemoryCache 和 Redis
Asp.net Core 缓存 MemoryCache 和 Redis 目录索引 [无私分享:ASP.NET CORE 项目实战]目录索引 简介 经过 N 久反复的尝试,翻阅了网上无数的资料,GitH ...
- Asp.net Core2.0 缓存 MemoryCache 和 Redis
自从使用Asp.net Core2.0 以来,不停摸索,查阅资料,这方面的资料是真的少,因此,在前人的基础上,摸索出了Asp.net Core2.0 缓存 MemoryCache 和 Redis的用法 ...
- 【无私分享:ASP.NET CORE 项目实战(第十一章)】Asp.net Core 缓存 MemoryCache 和 Redis
目录索引 [无私分享:ASP.NET CORE 项目实战]目录索引 简介 经过 N 久反复的尝试,翻阅了网上无数的资料,GitHub上下载了十几个源码参考, Memory 和 Redis 终于写出一个 ...
- 【NET Core】 缓存 MemoryCache 和 Redis
缓存接口 ICacheService using System; using System.Collections.Generic; using System.Threading.Tasks; nam ...
- 缓存-MemoryCache Class
这是使用MemoryCache缓存的一个例子. private void btnGet_Click(object sender, EventArgs e) { ObjectCache cache = ...
随机推荐
- 7.4 C++标准模板库(STL)的概念
参考:http://www.weixueyuan.net/view/6401.html 总结: 标准模板库为C++提供了完善的数据结构及算法. 标准模板库包括三部分:容器.算法和迭代器. 容器是对象 ...
- DevExpress v18.1新版亮点——DevExtreme篇(二)
用户界面套包DevExpress v18.1日前终于正式发布,本站将以连载的形式为大家介绍各版本新增内容.本文将介绍了DevExtreme JavaScript Controls v18.1 的新功能 ...
- 浅谈如何正确给table加边框
一般来说,给表格加边框都会出现不同的问题,以下是给表格加边框后展现比较好的方式 <style> table,table tr th, table tr td { border:1px so ...
- linux执行可执行文件时报xxx:not found
实际上是因为可执行文件执行时所依赖的动态链接库找不到,解决方法为在编译时加-static表示使用静态链接. 或者使用arm-linux-readelf -d +可执行文件,查看该可执行文件依赖的动态链 ...
- python中的pandas的两种基本使用
python中的pandas的两种基本使用2018年05月19日 16:03:36 木子柒努力成长 阅读数:480 一.pandas简介 pandas:panel data analysis(面板数据 ...
- Day1作业及默写
1.简述变量命名规范 变量由字母, 数字,下划线搭配组合而成 不可以⽤数字开头,更不不能是全数字 不能是pythond的关键字, 这些符号和字母已经被python占⽤, 不可以更改 不要⽤中文 名字要 ...
- DocumentFragment --更快捷操作DOM的途径
使用DocumentFragment将一批子元素添加到任何类似node的父节点上,对这批子元素的操作不需要一个真正的根节点.可以不依赖可见的DOM来构造一个DOM结构,而效率高是它真正的优势,试验表明 ...
- 【转载】 深度强化学习处理cartpole为什么reward很难超过200?
原贴地址: https://www.zhihu.com/question/266493753 一直在看强化学习方面的内容,cartpole是最简单的入门实验环境,最原始的评判标准是连续100次epis ...
- 一种绕过PTRACE反调试的办法
Linux 系统gdb等调试器,都是通过ptrace系统调用实现.Android加固中,ptrace自身防止调试器附加是一种常用的反调试手段. 调试时一般需要手工在ptrace处下断点,通过修改ptr ...
- pytorch实现autoencoder
关于autoencoder的内容简介可以参考这一篇博客,可以说写的是十分详细了https://sherlockliao.github.io/2017/06/24/vae/ 盗图一张,自动编码器讲述的是 ...