当前位置: 移动技术网 > IT编程>开发语言>c# > 详解Winform里面的缓存使用

详解Winform里面的缓存使用

2019年07月18日  | 移动技术网IT编程  | 我要评论
缓存在很多情况下需要用到,合理利用缓存可以一方面可以提高程序的响应速度,同时可以减少对特定资源访问的压力。本文主要针对自己在winform方面的缓存使用做一个引导性的介绍,

缓存在很多情况下需要用到,合理利用缓存可以一方面可以提高程序的响应速度,同时可以减少对特定资源访问的压力。本文主要针对自己在winform方面的缓存使用做一个引导性的介绍,希望大家能够从中了解一些缓存的使用场景和使用方法。缓存是一个中大型系统所必须考虑的问题。为了避免每次请求都去访问后台的资源(例如数据库),我们一般会考虑将一些更新不是很频繁的,可以重用的数据,通过一定的方式临时地保存起来,后续的请求根据情况可以直接访问这些保存起来的数据。这种机制就是所谓的缓存机制。

.net 4.0的缓存功能主要由三部分组成:system.runtime.caching,system.web.caching.cache和output cache。

system.runtime.caching这是在.net 4.0中新增的缓存框架,主要是使用memorycache对象,该对象存在于程序集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;
        }
    }

这个辅助类只有一个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(0, 30, 0));//30分钟过期
            return fullname;
        }

memorycachehelper的方法getcacheitem里面的func<t>我使用了一个匿名函数用来获取缓存的值。

复制代码 代码如下:

delegate() { return bllfactory<user>.instance.getfullnamebyid(userid.toint32()); }

而调用bllfactory<user>.instance.getfullnamebyid则是从数据库里面获取对应的数据了。

这样在第一次或者缓存过期的时候,自动调用业务对象类的方法来获取数据了。

最后,在界面上调用getuserfullname的方法即可实现基于缓存方式的调用,程序第一次使用的,碰到指定的键没有数据,就去数据库里面获取,以后碰到该键,则直接获取缓存的数据了。

下面图形是程序具体的实现效果。

当然,以上两种方式都还可以通过aop的注入方式实现代码的简化操作,不过由于对aop的引入,会涉及到更多的知识点,而且熟悉程序还不够,所以依然采用较为常用的方式来处理缓存的数据。

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网