仓酷云

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

[学习教程] ASP.NET网页编程之对.NET Framework 反射的深思

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

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

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

x
有专家说:java不是跨平台,java就是平台,这很好的定义了java的特点。有了java,你只需要等待java平台在新平台上移植。这还不错吧!只是,java不是一个平台,而是多个平台。你需要在这个java平台移植到另一个java平台。明晰的组件化方针是不是因在库间共享过量范例信息而失?也许您必要高效的强范例化数据存储,但假如每次工具模子开展后都必要更新您的数据库架构,那会泯灭很年夜本钱,以是您更乐意在运转时揣度出其范例架构吗?您必要托付能承受恣意用户工具的组件,并以某种智能化的体例处置它们吗?您但愿库的调方者能以编程体例向您申明它们的范例吗?
假如您发明本人在苦苦保持强范例化数据布局的同时,又期望于最年夜化运转时天真性,那末您也许会乐意思索反射,和它怎样改良您的软件。在本专栏中,我将切磋Microsoft.NETFramework中的System.Reflection定名空间,和它怎样为您的开辟体验供应助益。我将从一些复杂的示例入手下手,最初将报告怎样处置实际天下中的序列化情况。在此过程当中,我会展现反射和CodeDom怎样共同事情,以无效处置运转时数据。
在深切探求System.Reflection之前,我想先会商一下一样平常的反射编程。起首,反射可界说为由一个编程体系供应的任何功效,此功效使程序员能够在无需提早懂得其标识或正式布局的情形下反省和操纵代码实体。这部份内容良多,我将一一睁开申明。
起首,反射供应了甚么呢?您能用它做些甚么呢?我偏向于将典范的以反射为中央的义务分为两类:反省和操纵。反省必要剖析工具和范例,以搜集有关其界说和举动的布局化信息。除一些基础划定以外,一般这是在事前不懂得它们的情形下举行的。(比方,在.NETFramework中,任何器材都承继自System.Object,而且一个工具范例的援用一般是反射的一样平常出发点。)
操纵使用经由过程反省搜集到的信息静态地挪用代码,创立已发明范例的新实例,大概乃至能够轻松地震态从头布局化范例和工具。必要指出的一个要点是,关于年夜多半体系,在运转时操纵范例和工具,较之在源代码中静态地举行一律操纵,会招致功能下降。因为反射的静态特征,因而这是个需要的弃取,不外有良多技能和最好做法能够优化反射的功能。
那末,甚么是反射的方针呢?程序员实践反省和操纵甚么呢?在我对反射的界说中,我用了“代码实体”这个新术语,以夸大一个现实:从程序员的角度来讲,反射手艺偶然会使传统工具和范例之间的界线变得含混。比方,一个典范的以反射为中央的义务多是:
从工具O的句柄入手下手,并利用反射取得其相干界说(范例T)的句柄。
反省范例T,取得它的办法M的句柄。
挪用另外一个工具O’(一样是范例T)的办法M。
请注重,我在从一个实例穿越到它的底层范例,从这一范例到一个办法,以后又利用此办法的句柄在另外一个实例上挪用它—明显这是在源代码中利用传统的C#编程手艺没法完成的。鄙人文中切磋.NETFramework的System.Reflection以后,我会再次经由过程一个详细的例子来注释这一情况。
某些编程言语自己能够经由过程语法供应反射,而另外一些平台和框架(如.NETFramework)则将其作为体系库。不论以何种体例供应反射,在给定情况下利用反射手艺的大概性相称庞大。编程体系供应反射的才能取决于诸多要素:程序员很好天时用了编程言语的功效表达了他的观点吗?编译器是不是在输入中嵌进充足的布局化信息(元数据),以便利往后的解读?有无一个运转时子体系或主机注释器来消化这些元数据?平台库是不是以对程序员有效的体例,展现此注释了局?
假如您思想中设想的是一个庞大的、面向工具范例的体系,但在代码中却体现为复杂的、C言语作风的函数,并且没有正式的数据布局,那末明显您的程序不成能静态地揣度出,某变量v1的指针指向某品种型T的工具实例。由于究竟范例T是您思想中的观点,它从未在您的编程语句中明白地呈现。但假如您利用一种更加天真的面向工具言语(如C#)来表达程序的笼统布局,并间接引进范例T的观点,那末编译器就会把您的设法转换成某种往后能够经由过程符合的逻辑来了解的情势,就象大众言语运转时(CLR)或某种静态言语注释器所供应的一样。
反射完整是静态、运转时的手艺吗?复杂的说,不是如许。全部开辟和实行周期中,良多时分反射对开辟职员都可用且有效。一些编程言语经由过程自力编译器完成,这些编译器将初级代码间接转换成呆板可以辨认的指令。输入文件只包含编译过的输出,而且运转时没有效于承受不通明工具并静态剖析其界说的撑持逻辑。这恰是很多传统C编译器的情况。由于在方针可实行文件中几近没有撑持逻辑,因而您没法完成太多静态反射,但是编译器会不时供应静态反射—比方,广泛使用的typeof运算符同意程序员在编译时反省范例标识。
另外一种完整分歧的情形是,注释性编程言语老是经由过程主历程取得实行(剧本言语一般属于此类)。因为程序的完全界说是可用的(作为输出源代码),并跟完全的言语完成分离在一同(作为注释器自己),因而一切撑持自我剖析所需的手艺都到位了。这类静态言语频仍地供应周全反射功效,和一组用于静态剖析和操纵程序的丰厚工具。
.NETFrameworkCLR和它的承载言语如C#属于两头形状。编译器用来把源代码转换成IL和元数据,后者与源代码比拟虽属于较初级别大概较低“逻辑性”,但仍旧保存了良多笼统布局和范例信息。一旦CLR启动和承载了此程序,基类库(BCL)的System.Reflection库即可以利用此信息,并前往关于工具范例、范例成员、成员署名等的信息。别的,它也能够撑持挪用,包含前期绑定挪用。
.NET中的反射
要在用.NETFramework编程时使用反射,您可使用System.Reflection定名空间。此定名空间供应封装了良多运转时观点的类,比方程序集、模块、范例、办法、机关函数、字段和属性。中的表显现,System.Reflection中的类怎样与观点上运转时的对应项对应起来。
只管很主要,不外System.Reflection.Assembly和System.Reflection.Module次要用于定位新代码并将其加载到运转时。本专栏中,我暂不会商这些部分,而且假定一切相干代码都已加载。
要反省和操纵已加载代码,典范形式次要是System.Type。一般,您从取得一个所存眷运转时种别的System.Type实例入手下手(经由过程Object.GetType)。接着您可使用System.Type的各类办法,在System.Reflection中探究范例的界说并取得别的类的实例。比方,假如您对某特定办法感乐趣,并但愿取得此办法的一个System.Reflection.MethodInfo实例(大概经由过程Type.GetMethod)。一样,假如您对某字段感乐趣,并但愿取得此字段的一个System.Reflection.FieldInfo实例(大概经由过程Type.GetField)。
一旦取得一切需要的反射实例工具,便可依据必要遵守反省或操纵的步骤持续。反省时,您在反射类中利用各类形貌性属性,取得您必要的信息(这是通用范例吗?这是实例办法吗?)。操纵时,您能够静态地挪用并实行办法,经由过程挪用机关函数创立新工具,等等。
反省范例和成员
让我们跳转到一些代码中,探究怎样使用基础反射举行反省。我将会合会商范例剖析。从一个工具入手下手,我将检索它的范例,尔后考查几个成心思的成员。
起首必要注重的是,在类界说中,乍看起来讲明办法的篇幅比我预期的要多良多。这些分外的办法是从那里来的呢?任何精晓.NETFramework工具条理布局的人,城市辨认从通用基类Object本身承继的这些办法。(现实上,我起首利用了Object.GetType检索其范例。)别的,您能够看到属性的getter函数。如今,假如您只必要MyClass本身显式界说的函数,该怎样办呢?换句话说,您怎样埋没承继的函数?大概您大概只必要显式界说的实例函数?
任意在线看看MSDN,就会发明人人都乐意利用GetMethods第二个重载办法,它承受BindingFlags参数。经由过程分离来自BindingFlags列举中分歧的值,您可让函数仅前往所需的办法子集。交换GetMethods挪用,代之以:
GetMethods(BindingFlags.Instance|BindingFlags.DeclaredOnly|BindingFlags.Public)
了局是,您失掉以下输入(注重这里不存在静态匡助器函数和承继自System.Object的函数)。
以下为援用的内容:
ReflectionDemoExample1
  TypeName:MyClass
  MethodName:MyMethod1
  MethodName:MyMethod2
  MethodName:get_MyProperty
  PropertyName:MyProperty

假如您事前晓得范例称号(完整限制)和成员,又该怎样?您怎样完成从列举范例向检索范例的转换?有了前两个示例中的代码,您已有了可以完成基元类扫瞄器的基础组件。经由过程称号您能够找到一个运转时实体,然后列举其各类相干属性。
静态挪用代码
迄今为止,我已取得运转时工具的句柄(如范例和办法),仅作形貌用,比方输入它们的称号。可是怎样做得更多呢?怎样实践挪用某个办法呢?
此例的几个要点是:起首,从一个MyClass,mc1实例检索一个System.Type实例,然后,从该范例检索一个MethodInfo实例。最初,当挪用MethodInfo时,经由过程把它作为挪用的第一个参数来传送,将其绑定到另外一个MyClass(mc2)实例中。
后面讲过,关于您预期在源代码中见到的范例和工具利用之间的区分,这个示例使这类区分变得含混。逻辑上,您检索了一个办法的句柄,然后挪用该办法,就象它属于一个分歧的工具一样。关于熟习函数式编程言语的程序员来讲,这大概十拿九稳;但关于只熟习C#的程序员来讲,要分别工具完成和工具实例化,大概就不是那末直不雅了。
组合在一同
至此我已切磋过反省和挪用的基础道理,接上去我会器具体的例子把它们组合在一同。假想您但愿托付一个库,带有必需处置工具的静态匡助器函数。但在计划的时分,您对这些工具的范例没有任何观点!这要看函数挪用方的唆使,看他但愿怎样从这些工具中提取成心义的信息。函数将承受一个工具汇合,和一个办法的字符串形貌符。然后它将遍历该汇合,挪用每一个工具的办法,用一些函数聚合前往值。
就此例而言,我要声明一些束缚前提。起首,字符串参数形貌的办法(必需由每一个工具的底层范例完成)不会承受任何参数,并将前往一个整数。代码将遍历工具汇合,挪用指定的办法,慢慢盘算出一切值的均匀值。最初,由于这不是临盆代码,在乞降的时分我不必忧虑参数考证或整数溢出。
在扫瞄示例代码时,能够看到主函数与静态匡助器ComputeAverage之间的协定除工具本身的通用基类以外,其实不依附任何范例信息。换句话说,您能够完全改动正在传送的工具的范例和布局,但只需老是能利用字符串形貌一个办法,且该办法前往整数,ComputeAverage就能够一般事情!
必要注重的一个关头成绩跟埋没在最初这个例子中的MethodInfo(一样平常反射)有关。注重,在ComputeAverage的foreach轮回中,代码只从汇合中的第一个工具中抓取一个MethodInfo,然后绑定用于一切后续工具的挪用。正如编码所示,它运转优秀—这是MethodInfo缓存的一个复杂例子。但此处有一个基本性的范围。MethodInfo实例仅能由其检索工具一律层级范例的实例挪用。由于传进了IntReturner和SonOfIntReturner(承继自IntReturner)的实例,才干如许运转。
在示例代码中,已包括了名为EnemyOfIntReturner的类,它完成了与其他两个类不异的基础协定,但并没有共享任何罕见共享范例。换句话说,该接口逻辑上同等,但在范例层级上没有堆叠。要切磋MethodInfo在该情况下的利用,请实验向汇合增加其他工具,经由过程“newEnemyOfIntReturner(10)”失掉一个实例,再次运转示例。您会碰到一个非常,指出MethodInfo不克不及用于挪用指定的工具,由于它和取得MethodInfo时的原始范例完整有关(即便办法称号和基础协定是同等的)。要使您的代码到达临盆水准,您必要做好碰到这一情况的筹办。
一个大概的办理计划能够是经由过程本人剖析一切传进工具的范例,保存对其共享的范例层级(假如有)的注释。假如下一工具的范例与恣意已知范例层级相异,就必要猎取和存储一个新的MethodInfo。另外一办理计划是捕捉TargetException,偏重新猎取一个MethodInfo实例。这里提到的两种办理计划都各有其优弱点。JoelPobar为本杂志2007蒲月期写过一篇优异的文章,内容关于MethodInfo缓冲和我所尽力保举的反射功能。
但愿此示例演示的向使用程序或框架中增加反射,能够为往后的自界说或可扩大性增添更多的天真性。不成否定,较之本机编程言语中的一律逻辑,利用反射大概会有些烦琐。假如您感应对您或您的客户来讲,向代码中增加基于反射的前期绑定过于贫苦(究竟他们必要以某种体例在您的框架中申明他们的范例和代码),那末大概仅必要过度的天真性以获得某种均衡。
序列化的高效范例处置
至此我们已经由过程多少示例报告了.NET反射的基础道理,接上去让我们看一下实际天下中的情况。假如您的软件经由过程Web服务或其他历程外远程手艺与其他体系举行交互,那末您极可能已碰到序列化成绩。序列化实质上是将举动的、占用内存的工具,变化成合适线上传输或磁盘存储的数据格局。
.NETFramework中的System.Xml.Serialization定名空间供应了具有XmlSerializer的壮大序列化引擎,它可使用恣意托管工具,并将其转换成XML(往后也可将XML数据转换回范例化的工具实例,这一历程称之为反序列化)。XmlSerializer类是一种壮大的、企业停当的软件片段,假如您在项目中面对序列化成绩,它将是您的首选。但为了教授教养目标,我们来切磋怎样完成序列化(大概其他相似的运转时范例处置实例)。
假想情况:您正在托付一个框架,必要利用恣意用户范例的工具实例,并将其转换成某种智能型数据格局。比方,假定有一个驻留内存的工具,范例为以下所示的Address:
以下为援用的内容:
(pseudocode)
classAddress
{
 AddressIDid;
 StringStreet,City;
 StateTypeState;
 ZipCodeTypeZipCode;
}

怎样天生得当的数据暗示情势以便利往后利用?也许一个复杂的文本出现将办理这一成绩:
以下为援用的内容:
  Address:123
  Street:1MicrosoftWay
  City:Redmond
  State:WA
  Zip:98052

假如事前完整懂得必要转换的正式数据范例(比方本人编写代码时),事变就变得十分复杂:
以下为援用的内容:
foreach(AddressainAddressList)
{
 Console.WriteLine(“Address:{0}”,a.ID);
 Console.WriteLine(“        Street:{0}”,a.Street);
 ...//andsoon
}

但是,假如事后不晓得在运转时会碰到的数据范例,情形会变得非常风趣。您怎样编写象如许的一样平常框架代码?
MyFramework.TranslateObject(objectinput,MyOutputWriteroutput)
起首,您必要决意哪些范例成员对序列化有效。大概的情形包含仅捕捉特定范例的成员,比方基元体系范例,或供应一种机制以供范例作者申明哪些成员必要被序列化,比方在范例成员上利用自界说属性作为标志)。您仅能够捕捉特定范例的成员,比方基元体系范例,或范例作者可以申明哪些成员必要被序列化(大概的办法是在范例成员上利用自界说属性作为标志)。
一旦纪录分明必要转换的数据布局成员,您接着必要做的是编写逻辑,从传进的工具列举和检索它们。反射在这里担当了沉重的义务,让您既能够查询数据布局又能够查询数据值。
出于复杂性思索,我们来计划一个轻型转换引擎,失掉一个工具,猎取一切其大众属性值,经由过程间接挪用ToString将它们转换成字符串,然后将这些值序列化。关于一个名为“input”的给定工具,算法大抵以下:
挪用input.GetType以检索System.Type实例,该实例形貌了input的底层布局。
用Type.GetProperties和得当的BindingFlags参数,将大众属性作为PropertyInfo实例检索。
利用PropertyInfo.Name和PropertyInfo.GetValue,将属性作为键-值对检索。
在每一个值上挪用Object.ToString将其(经由过程基础体例)转化为字符串格局。
将工具范例的称号和属性称号、字符串值的汇合打包成准确的序列化格局。
这一算法分明简化了事变,同时也捉住了失掉运转时数据布局,并将其转化为自形貌型数据的要旨。但这里有一个成绩:功能。之条件到,反射关于范例处置和值检索的本钱都很高。本示例中,我在每一个供应范例的实例中实行了完全的范例剖析。
假如以某种体例能够捕捉或保存您关于范例布局的了解,以便往后不吃力地检索它,并无效处置该范例的新实例;换句话说,就是往前跳到示例算法中的步骤#3?好动静是,使用.NETFramework中的功效,完整大概做到这一点。一旦您了解了范例的数据布局,即可以利用CodeDom静态天生绑定到该数据布局的代码。您能够天生一个匡助器程序集,个中包括匡助器类和援用了传进范例并间接会见其属性的办法(相似托管代码中的任何其他属性),因而范例反省只会对功能发生一次影响。
如今我将修改这一算法。新范例:
取得对应于该范例的System.Type实例。
利用各类System.Type会见器检索架构(或最少检索对序列化有效的架构子集),比方属性称号、字段称号等。
利用架构信息天生匡助器程序集(经由过程CodeDom),该程序集与新范例相链接,并无效地处置实例。
在匡助器程序会合利用代码,提取实例数据。
依据必要序列化数据。
关于给定范例的一切传进数据,能够往前跳到步骤#4,较之显式反省每实例,这么做能够取得伟大的功能提拔。
我开辟了一个名为SimpleSerialization的基础序列化库,它用反射和CodeDom(本专栏中可下载)完成了这一算法。次要组件是一个名为SimpleSerializer的类,是用户用一个System.Type实例机关所得。在机关函数中,新的SimpleSerializer实例会剖析给定的范例,使用匡助器类天生一个一时程序集。该匡助器类会严密绑定到给定的数据范例,并且对实例的处置体例就象本人在完整事前懂得范例的情形下编写代码那样。
以下为援用的内容:
SimpleSerializer类有以下结构:
classSimpleSerializer
{
 publicclassSimpleSerializer(TypedataType);
 publicvoidSerialize(objectinput,SimpleDataWriterwriter);
}

复杂地使人惊讶!机关函数承当了最沉重的义务:它利用反射来剖析范例布局,然后用CodeDom天生匡助器程序集。SimpleDataWriter类只是用来分析罕见序列化形式的数据吸收器。
要序列化一个复杂的Address类实例,用上面的伪代码便可完成义务:
以下为援用的内容:
  SimpleSerializermySerializer=newSimpleSerializer(typeof(Address));
  SimpleDataWriterwriter=newSimpleDataWriter();
  mySerializer.Serialize(addressInstance,writer);

停止
激烈倡议您亲身试用一下示例代码,特别是SimpleSerialization库。我在SimpleSerializer一些风趣的部分都增加了正文,但愿可以有所匡助。固然,假如您必要在产物代码中举行严厉的序列化,那末的确要依托.NETFramework中供应的手艺(比方XmlSerializer)。但假如您发明在运转时必要利用恣意范例并能高效处置它们,我但愿您接纳我的SimpleSerialization库作为本人的计划。

有专家说:java不是跨平台,java就是平台,这很好的定义了java的特点。有了java,你只需要等待java平台在新平台上移植。这还不错吧!只是,java不是一个平台,而是多个平台。你需要在这个java平台移植到另一个java平台。
再见西城 该用户已被删除
沙发
发表于 2015-1-19 15:55:46 | 只看该作者
比如封装性、继承性、多态性等等,这就解决了刚才谈到的ASP的那些弱点。封装性使得代码逻辑清晰,易于管理,并且应用到ASP.Net上就可以使业务逻辑和Html页面分离,这样无论页面原型如何改变。
蒙在股里 该用户已被删除
板凳
发表于 2015-1-25 22:34:57 | 只看该作者
由于CGI程序每响应一个客户就会打开一个新的进程,所以,当有多个用户同时进行CGI请求的时候,服务器就会打开多个进程,这样就加重了服务器的负担,使服务器的执行效率变得越来越低下。
再现理想 该用户已被删除
地板
发表于 2015-2-4 10:02:08 | 只看该作者
主流网站开发语言之CGI:CGI就是公共网关接口(CommonGatewayInterface)的缩写。它是最早被用来建立动态网站的后台技术。这种技术可以使用各种语言来编写后台程序,例如C,C++,Java,Pascal等。
变相怪杰 该用户已被删除
5#
发表于 2015-2-9 22:02:12 | 只看该作者
使用普通的文本编辑器编写,如记事本就可以完成。由脚本在服务器上而不是客户端运行,ASP所使用的脚本语言都在服务端上运行,用户端的浏览器不需要提供任何别的支持,这样大提高了用户与服务器之间的交互的速度。
冷月葬花魂 该用户已被删除
6#
发表于 2015-2-27 23:20:22 | 只看该作者
微软又推出ASP.NET。这不是ASP的简单升级,而是全新一代的动态网页实现系统,用于一台WEB服务器建立强大的应用程序。是微软发展的新体系结构.NET的一部分,是ASP和.NET技术的结合。
若相依 该用户已被删除
7#
发表于 2015-3-9 15:40:54 | 只看该作者
通过这次激烈的讨论,我从大家身上学到了太多,开阔了眼界,不管是支持我的还是骂我的,都感谢你们。
admin 该用户已被删除
8#
发表于 2015-3-17 00:09:11 | 只看该作者
asp.net空间的支持有:ASP.NET1.1/虚拟目录/MicrosoftFrontPage2000扩展/CDONTS,同时他的网站上也提供了Asp.net的使用详解和程序源代码,相信对使用ASP.NET编程的程序员来说会非常有用哦!
飘灵儿 该用户已被删除
9#
发表于 2015-3-23 08:32:32 | 只看该作者
代码的可重用性差:由于是面向结构的编程方式,并且混合html,所以可能页面原型修改一点,整个程序都需要修改,更别提代码重用了。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

GMT+8, 2024-5-19 16:07

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

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