.NET 框架中的 XML:在 .NET 框架中使用 XML 架构执行代码生成[4]

[入库:2005年8月18日] [更新:2007年3月25日]

本文简介:选择自 dlt3e 的 blog

  我使用 type.getinterface() 而不是 type.isassignablefrom() 来测试接口实现情况,因为它能够快速跳到非托管代码,所以需要的开销较少。它们的效果是相同的,然而,使用后者将返回一个布尔值,而不是一个“类型”(如果未找到接口,则返回空值)。
  
  返回页首
  xmlserializer 的内部原理
  有了 codedom 以后,可以为追求自定义的开发人员带来大量能力和灵活性,但同时也带来了更大的责任。以这种方式修改代码会有危险,因为这会使代码不再按与架构兼容的方式进行序列化,或者 xmlserializer 功能被完全破坏,并针对意外的节点和特性引发异常,从而无法检索值,等等。
  
  因此,在处理生成的代码之前,绝对需要了解 xmlserializer 的内部原理,当然也就需要一种了解其内部原理的方法。
  
  当对象即将进行 xml 序列化时,将通过反射您传递给 xmlserializer 构造函数的类型来创建一个临时程序集(这就是您需要那么做的原因)。请等一下!不要因为“反射”一词而感到害怕!这对于每个类型只执行一次,并且在 appdomain 生命期内,将创建一对极为有效的 reader 和 writer 类来处理序列化和反序列化。
  
  这些类继承了 system.xml.serialization 命名空间中的 xmlserializationreader 和 xmlserializationwriter 公共类。它们还是 [thetopsecretclassname]。如果您希望看一下这些动态生成的类,您只需向应用程序配置文件(对于 web 应用程序,为 web.config)中添加以下设置:
  
  <system.diagnostics> <switches> <add name="xmlserialization.compilation" value="4"/> </switches> </system.diagnostics>
  
  现在,序列化程序将不会删除在该过程中生成的临时文件。对于 web 应用程序,这些文件将位于 c:\documents and settings\[yourmachinename]\aspnet\local settings\temp 中;或者,它们将位于当前用户的 local settings\temp 文件夹中。
  
  您将看到的代码就是当您希望有效地加载 .net 中的 xml 时需要编写的代码:使用嵌套的 while 和 if 语句进行读取,使用 xmlreader 方法在数据流中向下移动,等等。使用这些丑陋代码的目的就是使该处理过程真正地快起来。
  
  还可以通过使用 chris sells 的 xmlserializerprecompiler 工具来诊断所生成的这些类中的问题。
  
  我们可以查看此代码,以便分析在序列化程序所生成的类中进行更改的效果。
  
  返回页首
  通过 codedom 自定义
  某些自定义能够立即产生吸引力,因为它们是人们经常关心的与 xsd.exe 工具生成的类有关的问题。
  
  将字段转化为属性
  大多数开发人员抱怨的问题之一是,xsd.exe 工具生成的类带有公共字段,而不是由私有字段支持的属性。xmlserializer 生成的类通过使用常规的 [object].[member] 注释来读写该类的实例中的值。当然,从编译和源代码的角度来看,[member] 是字段还是属性没有什么区别。
  
  因此借助于 codedom,可以更改 xsd 的默认类。由于自定义 codegen 工具中内置的可扩展性,需要做的所有工作只是实现一个新的 icodeextension。该扩展将处理 codedom 树中的每个类型,而无论它是一个类还是一个结构:
  
  public class fieldstopropertiesextension : icodeextension
  {
   #region icodeextension members
   public void process( system.codedom.codenamespace code,
   system.xml.schema.xmlschema schema )
   {
   foreach ( codetypedeclaration type in code.types )
   {
   if ( type.isclass || type.isstruct )
   {
   // turn fields to props
  
  现在,我需要对该类型的每个成员(可能是字段、属性、方法等等)进行迭代,并且只处理 codememberfield 成员。不过,我不能只对 type.members 集合执行 foreach 操作,因为对于每个字段而言,我都需要向同一集合中添加属性。这将导致发生异常,因为 foreach 结构所使用的基础枚举数可能会无效。因此,我需要将当前成员复制到某个数组中,然后改为对该数组进行迭代:
  
  codetypemember[] members = new codetypemember[type.members.count];
  type.members.copyto( members, 0 );
  foreach ( codetypemember member in members )
  {
   // process fields only.
   if ( member is codememberfield )
   {
   // create property
  next, i create the new property:
  codememberproperty prop = new codememberproperty();
  prop.name = member.name;
  prop.attributes = member.attributes;
  prop.type = ( ( codememberfield )member ).type;
  // copy attributes from field to the property.
  prop.customattributes.addrange( member.customattributes );
  member.customattributes.clear();
  // copy comments from field to the property.
  prop.comments.addrange( member.comments );
  member.comments.clear();
  // modify the field.
  member.attributes = memberattributes.private;
  char[] letters = member.name.tochararray();
  letters[0] = char.tolower( letters[0] );
  member.name = string.concat( "_", new string( letters ) );
  
  请注意,我向新的属性中复制了字段名、它的成员特性以及类型。我将注释和自定义特性(xmlserialization 特性)移出字段,然后移到属性(addrange() 和 clear())中。最后,我将该字段变为私有字段,并将其首字母转化为小写,在它前面加上“_”字符,这对于由属性支持的字段而言,是一种相当通用的命名规则。
  
  但仍然缺少属性中最重要的元素:属性的 get 和 set 访问器的实现。因为它们只是对字段值进行传递,所以都非常简单:
  
  prop.hasget = true;
  prop.hasset = true;
  // add get/set statements pointing to field. generates:
  // return this._fieldname;
  prop.getstatements.add(
   new codemethodreturnstatement(
   new codefieldreferenceexpression(
   new codethisreferenceexpression(), member.name ) ) );
  // generates:
  // this._fieldname = value;
  prop.setstatements.add(

本文关键:.NET 框架中的 XML:在 .NET 框架中使用 XML 架构执行代码生成
 

本站最佳浏览方式为 分辨率 1024x768 IE 6.0(或更高版本的 IE浏览器)

go top