仓酷云

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 926|回复: 14
打印 上一主题 下一主题

[学习教程] ASP.NET网站制作之不利用反射举行C#属性的运转时静态会见仓酷云

[复制链接]
老尸 该用户已被删除
跳转到指定楼层
楼主
发表于 2015-1-18 11:18:48 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
也不知道,我同学昨天说数据挖掘很好。

  • 择要
  • 成绩的笼统

  • 没有优化的反射




    • 利用晚绑定优化的反射
    • 公允的比赛



  • 公允的完成体例

  • 换个思绪,最直白的完成体例
  • 运转时天生代码

  • 功能比拼


择要

纯真的反射带来天真性的同时,也年夜年夜下降了使用程序的效力。本文将使用C#的各类手艺,就怎样完成静态的办法挪用或属性会见做一些开端的研讨。但愿能够给一样必要进步反射功能的伴侣一些匡助。
成绩的笼统

反射能够用在良多的情形中,可是笼统来看就是用来会见编译时没法断定的成员。这成员能够是办法,也能够是属性。为了简化成绩,我们把成绩限制在属性的会见上。那末反射这个功效就能够笼统成上面这个接口。
  1. ///<summary>///Abstractionofthefunctionofaccessingmemberofaobjectatruntime.///</summary>publicinterfaceIMemberAccessor{///<summary>///Getthemembervalueofanobject.///</summary>///<paramname="instance">Theobjecttogetthemembervaluefrom.</param>///<paramname="memberName">Themembername,couldbethenameofapropertyoffield.Mustbepublicmember.</param>///<returns>Themembervalue</returns>objectGetValue(objectinstance,stringmemberName);///<summary>///Setthemembervalueofanobject.///</summary>///<paramname="instance">Theobjecttogetthemembervaluefrom.</param>///<paramname="memberName">Themembername,couldbethenameofapropertyoffield.Mustbepublicmember.</param>///<paramname="newValue">Thenewvalueofthepropertyfortheobjectinstance.</param>voidSetValue(objectinstance,stringmemberName,objectnewValue);}
复制代码
上面我们就来切磋这个接口怎样完成才干到达最高效力。
没有优化的反射

利用反射是完成下面接口的最直不雅最复杂的体例。代码以下:
  1. publicclassReflectionMemberAccessor:IMemberAccessor{publicobjectGetValue(objectinstance,stringmemberName){varpropertyInfo=instance.GetType().GetProperty(memberName);if(propertyInfo!=null){returnpropertyInfo.GetValue(instance,null);}returnnull;}publicvoidSetValue(objectinstance,stringmemberName,objectnewValue){varpropertyInfo=instance.GetType().GetProperty(memberName);if(propertyInfo!=null){propertyInfo.SetValue(instance,newValue,null);}}}
复制代码
可是这类体例的效力让人望而生畏。经由剖析我们能够发明最慢的部分就是GetValue和SetValue这两个挪用。
利用Delegate优化的反射

将PropertyInfo的XetValue代办署理起来是最复杂的进步功能办法。并且也已有良多人先容了这类体例,
1.FastDynamicPropertyFieldAccessors
2.晚绑定场景下对象属性赋值和取值能够不必要PropertyInfo
假如仅仅是看到他们的测试了局,会觉得晚绑定就能够让属性的静态会见的速率到达和间接取值一样的速率,会以为这生存何等优美啊。可是假如你真的把这个手艺用在个甚么中央会发明基本不是这么回事儿。实在的生存会如老赵写的FastReflectionLibrary中给出的测试了局一样平常。你会发明即便是晚绑定了或是Emit了,速率也是要比间接会见慢5-20倍。是老赵的完成体例有成绩吗?固然不是。
公允的比赛

这里明白一下我们要完成的功效是甚么?我们要完成的功效是,用一组办法或是形式,静态地会见任何一个对象上的任何一个属性。而后面那些看些优美的测试,都只是在测试晚绑定后的托付挪用的功能,而那测试用的晚绑定托付挪用都是针对某个类的某个属性的。这不是明摆着欺侮反射吗?固然测试用的反射Invoke也是针对一个属性,可是反射的通用版本的功能也是差未几的,Invoke才是损耗的年夜头。这也是数据统计蒙人的最多见的伎俩,用本人最好的一部分和对方的最差的一部分往对照。可是我们真正体贴的是全体。
用晚绑定这个特征往完成相似反射能完成的功效,是必要把每一个类的每一个属性都缓存起来,而且在利用的时分,依据以后对象的范例和所取的属性名查找对应的缓存好的晚绑定托付。这些功效在那些优美的测试了局中都完整没有表现出来。而老赵的FastReflectionLibary完成了这些功效,以是测试了局看上往要差良多。可是这才是实在的数据。
公允的完成体例

为了文章的完全起见,Delegate反射的完成体例以下。(我这里为了复杂起见,没有过量优化,假如你要用这个办法,仍是有很年夜的优化空间的。)
办法有两种,一种是利用Delegate.CreateDelegate函数。一种是利用ExpressionTree。
利用Delegate的中心代码分离以下所示:
  1. internalclassPropertyAccessor<T,P>:INamedMemberAccessor{privateFunc<T,P>GetValueDelegate;privateAction<T,P>SetValueDelegate;publicPropertyAccessor(Typetype,stringpropertyName){varpropertyInfo=type.GetProperty(propertyName);if(propertyInfo!=null){GetValueDelegate=(Func<T,P>)Delegate.CreateDelegate(typeof(Func<T,P>),propertyInfo.GetGetMethod());SetValueDelegate=(Action<T,P>)Delegate.CreateDelegate(typeof(Action<T,P>),propertyInfo.GetSetMethod());}}publicobjectGetValue(objectinstance){returnGetValueDelegate((T)instance);}publicvoidSetValue(objectinstance,objectnewValue){SetValueDelegate((T)instance,(P)newValue);}}
复制代码
Delegate.CreateDelegate在利用上有一个请求,其天生的Delegate的署名必需与Method的声明分歧。以是就有了下面利用泛型的体例。每一个PropertyAccessor是针对特定属性的,要真正用起来还要用Dictionary做下Mapping。以下所示:
  1. publicclassDelegatedReflectionMemberAccessor:IMemberAccessor{privatestaticDictionary<string,INamedMemberAccessor>accessorCache=newDictionary<string,INamedMemberAccessor>();publicobjectGetValue(objectinstance,stringmemberName){returnFindAccessor(instance,memberName).GetValue(instance);}publicvoidSetValue(objectinstance,stringmemberName,objectnewValue){FindAccessor(instance,memberName).SetValue(instance,newValue);}privateINamedMemberAccessorFindAccessor(objectinstance,stringmemberName){vartype=instance.GetType();varkey=type.FullName+memberName;INamedMemberAccessoraccessor;accessorCache.TryGetValue(key,outaccessor);if(accessor==null){varpropertyInfo=type.GetProperty(memberName);accessor=Activator.CreateInstance(typeof(PropertyAccessor<,>).MakeGenericType(type,propertyInfo.PropertyType),type,memberName)asINamedMemberAccessor;accessorCache.Add(key,accessor);}returnaccessor;}}
复制代码
用ExpressionTree的天生托付的时分,也会碰到范例的成绩,可是我们能够在ExpressionTree中对参数和前往值的范例举行处置,如许就不必要泛型的完成体例了。代码以下:
  1. publicclassDelegatedExpressionMemberAccessor:IMemberAccessor{privateDictionary<string,Func<object,object>>getValueDelegates=newDictionary<string,Func<object,object>>();privateDictionary<string,Action<object,object>>setValueDelegates=newDictionary<string,Action<object,object>>();publicobjectGetValue(objectinstance,stringmemberName){vartype=instance.GetType();varkey=type.FullName+memberName;Func<object,object>getValueDelegate;getValueDelegates.TryGetValue(key,outgetValueDelegate);if(getValueDelegate==null){varinfo=type.GetProperty(memberName);vartarget=Expression.Parameter(typeof(object),"target");vargetter=Expression.Lambda(typeof(Func<object,object>),Expression.Convert(Expression.Property(Expression.Convert(target,type),info),typeof(object)),target);getValueDelegate=(Func<object,object>)getter.Compile();getValueDelegates.Add(key,getValueDelegate);}returngetValueDelegate(instance);}}
复制代码
一个优化体例是,把这个类做成泛型类,那末key就能够只是memberName,如许就少往了type.FullName及一次字符串拼接操纵。功能能够进步很多。可是这类托付式的会见就是功能上的极限了吗?假如是我就不必来写这篇文章了。
固然盗窟却更间接的办法

我们的方针是静态的会见一个对象的一个属性,一谈到静态老是会天然而然地想到反射。实在另有一个对照朴实的体例。就是让这个类本人去向理。还记得一入手下手界说的IMemberAccessor接口吗?假如我们一切的类的都完成了这个接口,那末就间接挪用这个办法就是了。体例以下。
  1. publicclassMan:IMemberAccessor{publicstringName{get;set;}publicintAge{get;set;}publicDateTimeBirthday{get;set;}publicdoubleWeight{get;set;}publicdoubleHeight{get;set;}publicdecimalSalary{get;set;}publicboolMarried{get;set;}publicobjectGetValue(objectinstance,stringmemberName){varman=instanceasMan;if(man!=null){switch(memberName){case"Name":returnman.Name;case"Age":returnman.Age;case"Birthday":returnman.Birthday;case"Weight":returnman.Weight;case"Height":returnman.Height;case"Salary":returnman.Salary;case"Married":returnman.Married;default:returnnull;}}elsethrownewInvalidProgramException();}publicvoidSetValue(objectinstance,stringmemberName,objectnewValue){varman=instanceasMan;if(man!=null){switch(memberName){case"Name":man.Name=newValueasstring;break;case"Age":man.Age=Convert.ToInt32(newValue);break;case"Birthday":man.Birthday=Convert.ToDateTime(newValue);break;case"Weight":man.Weight=Convert.ToDouble(newValue);break;case"Height":man.Height=Convert.ToDouble(newValue);break;case"Salary":man.Salary=Convert.ToDecimal(newValue);break;case"Married":man.Married=Convert.ToBoolean(newValue);break;}}elsethrownewInvalidProgramException();}}
复制代码
有人大概会忧虑用这类体例,属性多了以后功能会下落。假如你用Reflector之类的工具反编译一下天生的DLL,你就不会有这类挂念了。C#关于switch语句有相称力度的优化。大略地讲,当属性少时会将switch天生为一堆ifelse。关于字段范例为string,也会主动地转成dictionary+int。
经由测试这类体例比下面的缓存晚绑定的体例要快一倍。可是优势也很分明,就是代码量太年夜了,并且不是一个好的计划,也不文雅。
用静态天生的工具函数让静态属性会见更快一些

下面的办法速率上实际上是最有上风的,可是缺少可操纵性。可是假如我们能为每一个类静态地天生两个Get/Set办法,那末这个办法就实践可用了。注重,这时候的静态挪用并非反射挪用了。天生的体例就是利用ExpressionTree编译出函数。
又由于这个体例是每一个类一个函数,不像之前的体例都是一个属性一个会见对象。我们就能够使用C#的另外一个特征来制止Dictionary的利用——泛型类中的静态成员:假如GenericClass<T>中界说的静态成员staticMember,那末GenericClass<A>中的staticMember和GenericClass<B>中的staticMember是不共享的。固然查找泛型类也必要分外的运转时事情,可是价值比Dictionary查询要低。
在这个办法中,既没有效到反射,也没有效到缓存Dictionary。能更好地包管与手工代码功能的分歧度。
完成的代码以下,鉴于代码量,只列出了get办法的代码:
  1. publicclassDynamicMethod<T>:IMemberAccessor{internalstaticFunc<object,string,object>GetValueDelegate;publicobjectGetValue(objectinstance,stringmemberName){returnGetValueDelegate(instance,memberName);}staticDynamicMethod(){GetValueDelegate=GenerateGetValue();}privatestaticFunc<object,string,object>GenerateGetValue(){vartype=typeof(T);varinstance=Expression.Parameter(typeof(object),"instance");varmemberName=Expression.Parameter(typeof(string),"memberName");varnameHash=Expression.Variable(typeof(int),"nameHash");varcalHash=Expression.Assign(nameHash,Expression.Call(memberName,typeof(object).GetMethod("GetHashCode")));varcases=newList<SwitchCase>();foreach(varpropertyInfointype.GetProperties()){varproperty=Expression.Property(Expression.Convert(instance,typeof(T)),propertyInfo.Name);varpropertyHash=Expression.Constant(propertyInfo.Name.GetHashCode(),typeof(int));cases.Add(Expression.SwitchCase(Expression.Convert(property,typeof(object)),propertyHash));}varswitchEx=Expression.Switch(nameHash,Expression.Constant(null),cases.ToArray());varmethodBody=Expression.Block(typeof(object),new[]{nameHash},calHash,switchEx);returnExpression.Lambda<Func<object,string,object>>(methodBody,instance,memberName).Compile();}}
复制代码
可是,好吧,成绩来了。泛型类就意味着必要在写代码的时分,大概说编译时晓得对象的范例。如许也不切合我们一入手下手界说的方针。固然办理计划也是有的,就是再把谁人Dictionary缓存请返来。详细体例参考下面的给Delegate做缓存的代码。
另有一个成绩就是,这类Switch代码的功能会跟着Property数目的增加而出现大抵为线性的下落。会终极差于Delegate缓存体例的挪用。可是幸亏这个临界点对照高,大抵在40个到60个属性摆布。
功能测试

我们先把一切的体例列一下。

  • 间接的对象属性读写
  • 纯真的反射
  • 利用Delegate.CreateDelegate天生托付并缓存
  • 利用ExpressionTree天生属性会见托付并缓存
  • 让对象本人完成IMemberAccessor接口,利用SwitchCase。
  • 为每一个类天生IMemberAcessor接口所界说的函数。(非泛型体例挪用)
  • 为每一个类天生IMemberAcessor接口所界说的函数。(泛型体例挪用)
我们来看一下这6种完成对应的7种利用体例的功能。
Debug:实行1000万次
办法第一次了局第二次了局间接挪用208ms227ms反射挪用21376ms21802msExpression托付4341ms4176msCreateDelegate托付4204ms4111ms对象本身Switch1653ms1338ms静态天生函数2123ms2051ms(泛型)静态天生函数1167ms1157msRelease:实行1000万次
办法第一次了局第二次了局间接挪用73ms77ms反射挪用20693ms21229msExpression托付3852ms3853msCreateDelegate托付3704ms3748ms对象本身Switch1105ms1116ms静态天生函数1678ms1722ms(泛型)静态天生函数843ms862ms静态天生的函数比手写的Switch还要快的缘故原由是手写的Switch要利用到Dictionary来将String范例的字段名映照到int值。而我们天生的Switch是间接利用属性的hashcode值举行的。以是会更快。完全的代码能够从这里下载到。
以前学了大概半年时间的asp(没有机会做大系统,最多是自己对公司系统做些调整和修改还有一些小程序)。应该说开始接触asp.net是今年元月5号的事。现在很想把公司的系统重新用.net来架构,却不知道如何下手。
若天明 该用户已被删除
沙发
发表于 2015-1-20 19:59:39 | 只看该作者
但是目前在CGI中使用的最为广泛的是Perl语言。所以,狭义上所指的CGI程序一般都是指Perl程序,一般CGI程序的后缀都是.pl或者.cgi。
小妖女 该用户已被删除
板凳
发表于 2015-1-25 19:03:30 | 只看该作者
关于ASP.NET功能上,ASP.NET比微软以前的ASP(96年出现)有更强大的library,更好的稳定性。ASP.NET可以使用.NETFramework中所有组件(也就是说.NET能实现的,ASP.NET一样能实现)。
谁可相欹 该用户已被删除
地板
发表于 2015-2-3 13:57:33 | 只看该作者
我觉得什么语言,精通就好,你要做的就是比其他80%的人都厉害,你就能得到只有20%的人才能得到的高薪。
活着的死人 该用户已被删除
5#
发表于 2015-2-6 07:58:07 | 只看该作者
在调试JSP代码时,如果程序出错,JSP服务器会返回出错信息,并在浏览器中显示。这时,由于JSP是先被转换成Servlet后再运行的,所以,浏览器中所显示的代码出错的行数并不是JSP源代码的行数。
分手快乐 该用户已被删除
6#
发表于 2015-2-7 23:00:12 | 只看该作者
ASP.NET:ASP.net是Microsoft.net的一部分,作为战略产品,不仅仅是ActiveServerPage(ASP)的下一个版本;它还提供了一个统一的Web开发模型,其中包括开发人员生成企业级Web应用程序所需的各种服务。ASP.NET的语法在很大程度上与ASP兼容,同时它还提供一种新的编程模型和结构,可生成伸缩性和稳定性更好的应用程序,并提供更好的安全保护。
再见西城 该用户已被删除
7#
发表于 2015-2-9 04:35:20 | 只看该作者
逐步缩小出错代码段的范围,最终确定错误代码的位置。
山那边是海 该用户已被删除
8#
发表于 2015-2-26 22:18:53 | 只看该作者
比如封装性、继承性、多态性等等,这就解决了刚才谈到的ASP的那些弱点。封装性使得代码逻辑清晰,易于管理,并且应用到ASP.Net上就可以使业务逻辑和Html页面分离,这样无论页面原型如何改变。
再现理想 该用户已被删除
9#
发表于 2015-3-1 17:34:08 | 只看该作者
ASP.Net摆脱了以前ASP使用脚本语言来编程的缺点,理论上可以使用任何编程语言包括C++,VB,JS等等,当然,最合适的编程语言还是MS为.NetFrmaework专门推出的C(读csharp)。
简单生活 该用户已被删除
10#
发表于 2015-3-10 21:34:22 | 只看该作者
可以通过在现有ASP应用程序中逐渐添加ASP.NET功能,随时增强ASP应用程序的功能。ASP.NET是一个已编译的、基于.NET的环境,可以用任何与.NET兼容的语言(包括VisualBasic.NET、C#和JScript.NET.)创作应用程序。另外,任何ASP.NET应用程序都可以使用整个.NETFramework。开发人员可以方便地获得这些技术的优点,其中包括托管的公共语言运行库环境、类型安全、继承等等。
第二个灵魂 该用户已被删除
11#
发表于 2015-3-11 04:01:48 | 只看该作者
Asp.net脚本的出现,为ASP空间带来了更高的稳定性,同时也为程序员建站提供更高环境!
灵魂腐蚀 该用户已被删除
12#
发表于 2015-3-11 21:19:23 | 只看该作者
能产生和执行动态、交互式、高效率的站占服务器的应用程序。运用ASP可将VBscript、javascript等脚本语言嵌入到HTML中,便可快速完成网站的应用程序,无需编译,可在服务器端直接执行。容易编写。
愤怒的大鸟 该用户已被删除
13#
发表于 2015-3-11 22:25:48 | 只看该作者
最强的技术支持WebService,而且有.NET的所有library做后盾。而且ASP.NET在.NET3.5中还有微软专门为AJAX开发的功能--ASP.NETAJAX。
不帅 该用户已被删除
14#
发表于 2015-3-12 20:44:26 | 只看该作者
但是java靠开源打出的一片天地,特别是在微软的垄断下能打开今天的局面还是有它的生命力的。
飘灵儿 该用户已被删除
15#
发表于 2015-3-20 02:26:02 | 只看该作者
如今主流的Web服务器软件主要由IIS或Apache组成。IIS支持ASP且只能运行在Windows平台下,Apache支持PHP,CGI,JSP且可运行于多种平台,虽然Apache是世界使用排名第一的Web服务器平台。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|仓酷云 鄂ICP备14007578号-2

GMT+8, 2024-12-23 17:58

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表