缓存在很多情况下需要用到,合理利用缓存可以一方面可以提高程序的响应速度,同时可以减少对特定资源访问的压力。本文主要针对自己在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使用的更多相关文章

  1. Winform里面的缓存使用

    缓存在很多情况下需要用到,合理利用缓存可以一方面可以提高程序的响应速度,同时可以减少对特定资源访问的压力.本文主要针对自己在Winform方面的缓存使用做一个引导性的介绍,希望大家能够从中了解一些缓存 ...

  2. 详解Winform里面的缓存使用

    缓存在很多情况下需要用到,合理利用缓存可以一方面可以提高程序的响应速度,同时可以减少对特定资源访问的压力.本文主要针对自己在Winform方面的缓存使用做一个引导性的介绍,希望大家能够从中了解一些缓存 ...

  3. NET下三种缓存机制(Winform里面的缓存使用 )

    原文(http://www.cnblogs.com/wuhuacong/p/3526335.html)非常感谢伍华聪作者的分享! 缓存在很多情况下需要用到,合理利用缓存可以一方面可以提高程序的响应速度 ...

  4. winform中使用缓存

    文章:Winform里面的缓存使用 另外一篇文章:缓存-MemoryCache Class

  5. Asp.net Core 缓存 MemoryCache 和 Redis

    Asp.net Core 缓存 MemoryCache 和 Redis 目录索引 [无私分享:ASP.NET CORE 项目实战]目录索引 简介 经过 N 久反复的尝试,翻阅了网上无数的资料,GitH ...

  6. Asp.net Core2.0 缓存 MemoryCache 和 Redis

    自从使用Asp.net Core2.0 以来,不停摸索,查阅资料,这方面的资料是真的少,因此,在前人的基础上,摸索出了Asp.net Core2.0 缓存 MemoryCache 和 Redis的用法 ...

  7. 【无私分享:ASP.NET CORE 项目实战(第十一章)】Asp.net Core 缓存 MemoryCache 和 Redis

    目录索引 [无私分享:ASP.NET CORE 项目实战]目录索引 简介 经过 N 久反复的尝试,翻阅了网上无数的资料,GitHub上下载了十几个源码参考, Memory 和 Redis 终于写出一个 ...

  8. 【NET Core】 缓存 MemoryCache 和 Redis

    缓存接口 ICacheService using System; using System.Collections.Generic; using System.Threading.Tasks; nam ...

  9. 缓存-MemoryCache Class

    这是使用MemoryCache缓存的一个例子. private void btnGet_Click(object sender, EventArgs e) { ObjectCache cache = ...

随机推荐

  1. 输入系统:epoll & inotify

    一.epoll 作用:检测一个或多个文件的可读.可写等属性变化: 代码示例: #include <sys/epoll.h> #include <stdio.h> #includ ...

  2. Capjoint的merrcmd生成二次曲线的misfit原理

    http://www.personal.psu.edu/jhm/f90/lectures/lsq2.html

  3. jquery转换json对象为字符串

    jquery转换json对象为字符串 JSON.stringify(jsonObject),可用于单个JSON对象,也可用于JSON数组 alert(JSON.stringify(jsonObject ...

  4. L293 给地球降温

    Countries look at ways to tinker with Earth’s thermostat The idea of cooling the climate with strato ...

  5. Oracle触发器报错

    Oracle编写触发器时,执行时候报错,错误提示信息如上图所示,类似这种一般都是触发器语句有语法错误.重新审核语句,并再次执行. 如果用的是pl/sql developer的话,可以查看当前用户下的对 ...

  6. 【python】pandas display选项

    import pandas as pd 1.pd.set_option('expand_frame_repr', False) True就是可以换行显示.设置成False的时候不允许换行 2.pd.s ...

  7. golang切片类型

    切片slice 其本身并不是数组,它指向底层的数组 作为变长数组的替代方案,可以关联底层数组的局部或全部 为引用类型 可以直接创建或从底层数组获取生成 使用len()获取元素个数,cap()获取容量 ...

  8. FCC JS基础算法题(6):Truncate a string(截断字符串)

    先看一下题目描述: 如果字符串的长度比指定的参数num长,则把多余的部分用...来表示.切记,插入到字符串尾部的三个点号也会计入字符串的长度.但是,如果指定的参数num小于或等于3,则添加的三个点号不 ...

  9. ubantu安装node、npm、cnpm、live-server

    更新ubuntu软件源 sudo apt-get update sudo apt-get install -y python-software-properties software-properti ...

  10. 2019-03-25-day018-面向对象

    re模块 字符串匹配 列表 = findall(正则表达式,待匹配的字符串) 找所有 结果集 = search 找第一个,结果集.group() 结果集 = match 从第一个字符开始匹配,结果集. ...