国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
.NET 框架中的 XML:在 .NET 框架中使用 XML 架構(gòu)執(zhí)行代碼生成(2)
擴(kuò)展 XSD 處理
  為了自定義處理過程,我需要將信息傳遞給該工具,以便它知道要更改或處理的內(nèi)容。此時(shí)有兩種主要選擇:
  
  • 向 XSD 根 元素添加可被我的處理器理解的特性(可能添加很多),以便應(yīng)用自定義,這種方法類似于類型化數(shù)據(jù)集方法。 單擊此處可獲得更多相關(guān)信息。
  
  • 通過架構(gòu)注釋使用內(nèi)置的 XSD 可擴(kuò)展性,以便任意進(jìn)行自定義。它只需向某種代碼生成管線中添加類型,即可在基本生成發(fā)生后執(zhí)行。
  
  
  第一種方法最初可能很有吸引力,因?yàn)樗浅:?jiǎn)單。我只需添加一個(gè)特性,然后相應(yīng)地修改處理器以檢查該特性:
  
  架構(gòu):
  
  <xs:schema elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:code="http://weblogs.asp.net/cazzu" code:fieldsToProperties="true">
  
  代碼:
  
  XmlSchema xsd;
  // Load the XmlSchema.
  ...
  foreach (XmlAttribute attr in xsd.UnhandledAttributes)
  {
   if (attr.NamespaceURI == "http://weblogs.asp.net/cazzu")
   {
   switch (attr.LocalName)
   {
   case "fieldsToProperties":
   if (bool.Parse(attr.value)) ConvertFieldsToProperties(ns);
   break;
   ...
   }
   }
  }
  
  這正是您通常會(huì)在其他從 xsd 到類的生成器中看到的方法(您可以在 Code Generation Network 中找到大量類似的生成器)。遺憾的是,該方法將導(dǎo)致長(zhǎng)長(zhǎng)的 switch 語(yǔ)句、無盡的特性,并最終導(dǎo)致代碼難以維護(hù)并缺乏可擴(kuò)展性。
  
  第二種方法更為健壯,因?yàn)樗鼜囊婚_始就考慮了可擴(kuò)展性。XSD 通過 元素提供此類擴(kuò)展工具,該元素可以是架構(gòu)中幾乎所有項(xiàng)目的子元素。我將利用該元素及其 子元素,以便使開發(fā)人員可以指定運(yùn)行哪些(任意)擴(kuò)展以及按什么順序運(yùn)行。這樣的擴(kuò)展架構(gòu)將如下所示:
  
  <xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:annotation> <xs:appinfo> <Code xmlns="http://weblogs.asp.net/cazzu"> <Extension Type="XsdGenerator.Extensions.FieldsToPropertiesExtension, XsdGenerator.CustomTool" /> </Code> </xs:appinfo> </xs:annotation>
  
  當(dāng)然,每個(gè)擴(kuò)展都將需要實(shí)現(xiàn)一個(gè)公共接口,以便自定義工具可以輕松地執(zhí)行各個(gè)擴(kuò)展:
  
  public interface ICodeExtension { void Process( System.CodeDom.CodeNamespace code, System.Xml.Schema.XmlSchema schema ); }
  
  通過預(yù)先提供此類可擴(kuò)展性,當(dāng)產(chǎn)生新的自定義需要時(shí),就可以很容易地進(jìn)行其他自定義。甚至還可以從一開始就將最基本的代碼實(shí)現(xiàn)為擴(kuò)展。
  
  可擴(kuò)展的代碼生成工具
  我將修改 Processor 類以添加這種新功能,并且將簡(jiǎn)單地從架構(gòu)中檢索各個(gè) 元素。盡管如此,這里還需要提出一個(gè)警告:與那些為元素、特性、類型等公開的 Post Schema Compilation Infoset 屬性不同,在架構(gòu)級(jí)別沒有針對(duì)注釋的類型化屬性。也就是說,沒有 XmlSchema.Annotations 屬性。因此,需要對(duì) XmlSchema.Items 的一般性預(yù)編譯屬性進(jìn)行迭代,以便查找注釋。而且,在檢測(cè)到 XmlSchemaAnnotation 項(xiàng)目之后,再次需要對(duì)其自己的 Items 一般性集合進(jìn)行迭代,這是因?yàn)槌?子元素以外,還可能有 子元素,而它也缺少類型化屬性。當(dāng)最終通過 XmlSchemaAppInfo.Markup 屬性獲得 appinfo 的內(nèi)容之后,我們所得到的全部?jī)?nèi)容是一個(gè) XmlNode 對(duì)象數(shù)組。您可以想像如何進(jìn)行后續(xù)處理:對(duì)節(jié)點(diǎn)進(jìn)行迭代,再對(duì)其子元素進(jìn)行迭代,等等。這將產(chǎn)生非常丑陋的代碼。
  
  值得慶幸的是,XSD 文件只是一個(gè) XML 文件,因此可以使用 XPath 來對(duì)其進(jìn)行查詢。
  
  為了提高執(zhí)行速度,我將在 Processor 類中保留 XPath 的靜態(tài)編譯表達(dá)式,它將在其靜態(tài)構(gòu)造函數(shù)中進(jìn)行初始化:
  
  public sealed class Processor
  {
   public const string ExtensionNamespace = "http://weblogs.asp.net/cazzu";
   private static XPathExpression Extensions;
   static Processor()
   {
   XPathNavigator nav = new XmlDocument().CreateNavigator();
   // Select all extension types.
   Extensions = nav.Compile
   ("/xs:schema/xs:annotation/xs:appinfo/kzu:Code/kzu:Extension/@Type");
   // Create and set namespace resolution context.
   XmlNamespaceManager nsmgr = new XmlNamespaceManager(nav.NameTable);
   nsmgr.AddNamespace("xs", XmlSchema.Namespace);
   nsmgr.AddNamespace("kzu", ExtensionNamespace);
   Extensions.SetContext(nsmgr);
   }
  
  注 有關(guān) XPath 預(yù)編譯和執(zhí)行的優(yōu)點(diǎn)、細(xì)節(jié)和高級(jí)應(yīng)用的更多信息,請(qǐng)參閱 Performant XML (I): Dynamic XPath expressions compilation 和 Performant XML (II): XPath execution tips。
  
  Process() 方法需要在將 CodeNamespace 返回給調(diào)用方之前,執(zhí)行該查詢并執(zhí)行它找到的每個(gè) ICodeExtension 類型:
  
  XPathNavigator nav;
  using ( FileStream fs = new FileStream( xsdFile, FileMode.Open ) )
  { nav = new XPathDocument( fs ).CreateNavigator(); }
  XPathNodeIterator it = nav.Select( Extensions );
  while ( it.MoveNext() )
  {
   Type t = Type.GetType( it.Current.value, true );
   // Is the type an ICodeExtension?
   Type iface = t.GetInterface( typeof( ICodeExtension ).Name );
   if (iface == null)
   throw new ArgumentException( "Invalid extension type ‘" +
   it.Current.value + "‘." );
   ICodeExtension ext = ( ICodeExtension ) Activator.CreateInstance( t );
   // Run it!
   ext.Process( ns, xsd );
  }
  return ns;
  
  我使用 Type.GetInterface() 而不是 Type.IsAssignableFrom() 來測(cè)試接口實(shí)現(xiàn)情況,因?yàn)樗軌蚩焖偬椒峭泄艽a,所以需要的開銷較少。它們的效果是相同的,然而,使用后者將返回一個(gè)布爾值,而不是一個(gè)“類型”(如果未找到接口,則返回空值)。
  
  返回頁(yè)首
  XmlSerializer 的內(nèi)部原理
  有了 CodeDom 以后,可以為追求自定義的開發(fā)人員帶來大量能力和靈活性,但同時(shí)也帶來了更大的責(zé)任。以這種方式修改代碼會(huì)有危險(xiǎn),因?yàn)檫@會(huì)使代碼不再按與架構(gòu)兼容的方式進(jìn)行序列化,或者 XmlSerializer 功能被完全破壞,并針對(duì)意外的節(jié)點(diǎn)和特性引發(fā)異常,從而無法檢索值,等等。
  
  因此,在處理生成的代碼之前,絕對(duì)需要了解 XmlSerializer 的內(nèi)部原理,當(dāng)然也就需要一種了解其內(nèi)部原理的方法。
  
  當(dāng)對(duì)象即將進(jìn)行 XML 序列化時(shí),將通過反射您傳遞給 XmlSerializer 構(gòu)造函數(shù)的類型來創(chuàng)建一個(gè)臨時(shí)程序集(這就是您需要那么做的原因)。請(qǐng)等一下!不要因?yàn)?#8220;反射”一詞而感到害怕!這對(duì)于每個(gè)類型只執(zhí)行一次,并且在 AppDomain 生命期內(nèi),將創(chuàng)建一對(duì)極為有效的 Reader 和 Writer 類來處理序列化和反序列化。
  
  這些類繼承了 System.Xml.Serialization 命名空間中的 XmlSerializationReader 和 XmlSerializationWriter 公共類。它們還是 [TheTopSecretClassName]。如果您希望看一下這些動(dòng)態(tài)生成的類,您只需向應(yīng)用程序配置文件(對(duì)于 Web 應(yīng)用程序,為 web.config)中添加以下設(shè)置:
  
  <system.diagnostics> <switches> <add name="XmlSerialization.Compilation" value="4"/> </switches> </system.diagnostics>
  
  現(xiàn)在,序列化程序?qū)⒉粫?huì)刪除在該過程中生成的臨時(shí)文件。對(duì)于 Web 應(yīng)用程序,這些文件將位于 C:\Documents and Settings\[YourMachineName]\ASPNET\Local Settings\Temp 中;或者,它們將位于當(dāng)前用戶的 Local Settings\Temp 文件夾中。
  
  您將看到的代碼就是當(dāng)您希望有效地加載 .NET 中的 XML 時(shí)需要編寫的代碼:使用嵌套的 while 和 if 語(yǔ)句進(jìn)行讀取,使用 XmlReader 方法在數(shù)據(jù)流中向下移動(dòng),等等。使用這些丑陋代碼的目的就是使該處理過程真正地快起來。
  
  還可以通過使用 Chris Sells 的 XmlSerializerPreCompiler 工具來診斷所生成的這些類中的問題。
  
  我們可以查看此代碼,以便分析在序列化程序所生成的類中進(jìn)行更改的效果。
  
  返回頁(yè)首
  通過 CodeDom 自定義
  某些自定義能夠立即產(chǎn)生吸引力,因?yàn)樗鼈兪侨藗兘?jīng)常關(guān)心的與 xsd.exe 工具生成的類有關(guān)的問題。
  
  將字段轉(zhuǎn)化為屬性
  大多數(shù)開發(fā)人員抱怨的問題之一是,xsd.exe 工具生成的類帶有公共字段,而不是由私有字段支持的屬性。XmlSerializer 生成的類通過使用常規(guī)的 [object].[member] 注釋來讀寫該類的實(shí)例中的值。當(dāng)然,從編譯和源代碼的角度來看,[member] 是字段還是屬性沒有什么區(qū)別。
  
  因此借助于 CodeDom,可以更改 XSD 的默認(rèn)類。由于自定義 codegen 工具中內(nèi)置的可擴(kuò)展性,需要做的所有工作只是實(shí)現(xiàn)一個(gè)新的 ICodeExtension。該擴(kuò)展將處理 CodeDom 樹中的每個(gè)類型,而無論它是一個(gè)類還是一個(gè)結(jié)構(gòu):
  
  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
  
  現(xiàn)在,我需要對(duì)該類型的每個(gè)成員(可能是字段、屬性、方法等等)進(jìn)行迭代,并且只處理 CodeMemberField 成員。不過,我不能只對(duì) type.Members 集合執(zhí)行 foreach 操作,因?yàn)閷?duì)于每個(gè)字段而言,我都需要向同一集合中添加屬性。這將導(dǎo)致發(fā)生異常,因?yàn)?foreach 結(jié)構(gòu)所使用的基礎(chǔ)枚舉數(shù)可能會(huì)無效。因此,我需要將當(dāng)前成員復(fù)制到某個(gè)數(shù)組中,然后改為對(duì)該數(shù)組進(jìn)行迭代:
  
  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 ) );
  
  請(qǐng)注意,我向新的屬性中復(fù)制了字段名、它的成員特性以及類型。我將注釋和自定義特性(XmlSerialization 特性)移出字段,然后移到屬性(AddRange() 和 Clear())中。最后,我將該字段變?yōu)樗接凶侄?,并將其首字母轉(zhuǎn)化為小寫,在它前面加上“_”字符,這對(duì)于由屬性支持的字段而言,是一種相當(dāng)通用的命名規(guī)則。
  
  但仍然缺少屬性中最重要的元素:屬性的 get 和 set 訪問器的實(shí)現(xiàn)。因?yàn)樗鼈冎皇菍?duì)字段值進(jìn)行傳遞,所以都非常簡(jiǎn)單:
  
  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(
   new CodeAssignStatement(
   new CodeFieldReferenceExpression(
   new CodeThisReferenceExpression(), member.Name ),
   new CodeArgumentReferenceExpression( "value" ) ) );
  
  最后,我們只需向該類型中添加新的屬性:
  
  type.Members.Add( prop );
  }
  
  好了,先前的架構(gòu)通過該工具生成以下代碼:
  
  /// <remarks/> [System.Xml.Serialization.XmlRootAttribute(Namespace="", IsNullable=false)] public class Publisher { /// <remarks/> public string pub_id;
  
  向該架構(gòu)添加相應(yīng)的擴(kuò)展以后:
  
  <xs:schema elementFormDefault="qualified" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:annotation> <xs:appinfo> <Code xmlns="http://weblogs.asp.net/cazzu"> <Extension Type="XsdGenerator.Extensions.FieldsToPropertiesExtension, XsdGenerator.CustomTool" /> </Code> </xs:appinfo> </xs:annotation> ...
  
  該架構(gòu)現(xiàn)在將生成:
  
  ///
  [System.Xml.Serialization.XmlRootAttribute(Namespace="", IsNullable=false)]
  public class Publisher
  {
   private string _pub_id;
   ///
   public string pub_id
   {
   get
   {
   return this._pub_id;
   }
   set
   {
   this._pub_id = value;
   }
   }
  
  使用集合而不是數(shù)組
  對(duì)于任何比較像樣的讀寫(具有 get 和 set 屬性)對(duì)象模型而言,要使其可供程序員方便地使用,它的多值屬性都應(yīng)該基于集合,而不是基于數(shù)組。這樣做會(huì)使修改值和操縱對(duì)象圖變得更為容易。通常的方法涉及到從 CollectionBase 派生一個(gè)新的類型化集合類。
  
  在將更改提交給 CodeDom 之前,XmlSerializer 支持必須對(duì)集合進(jìn)行檢查。在分析和反射要序列化的類型的類的內(nèi)部深處,有一個(gè)名為 TypeScope 的內(nèi)部類。TypeScope 負(fù)責(zé)確保生成序列化代碼。它包含一個(gè)有趣的方法,名為 ImportTypeDesc,該方法執(zhí)行大多數(shù)檢查工作并且為支持的類型生成信息。在這里,我們找到了對(duì) IXmlSerializable(它檢查其成員中的安全特性)、數(shù)組(必須具有等于 1 的秩)、Enums、XmlNode、XmlAttribute 和 XmlElement 等的特殊支持。
  
  尤其是對(duì)集合而言,導(dǎo)入方法檢查實(shí)現(xiàn) ICollection 的類型,該類型必須滿足下列規(guī)則:
  
  • 必須具有一個(gè) Add 方法,該方法不是由該接口定義的,因?yàn)樗ǔJ菫樵摷蠈⒁菁{的專用類型而創(chuàng)建的。
  
  • 不得通過該集合實(shí)現(xiàn) IDictionary。
  
  • 必須具有一個(gè)默認(rèn)成員(即一個(gè)索引器)并且該成員具有一個(gè)類型為 System.Int32 (C# int) 的參數(shù)。系統(tǒng)將在所有類型層次結(jié)構(gòu)中搜索這樣的成員。
  
  • 在 Add、Count 和索引器中不能有任何安全特性。
  
  
  在驗(yàn)證上述信息以后,生成的派生自 XmlSerializationWriter 的專用類在為我們的類型編寫 XML 輸出時(shí),將使用 Count 屬性進(jìn)行迭代,而不使用基于數(shù)組的屬性的 Lenth:
  
  MyAssembly.MyCollection a = (MyAssembly.MyCollection)o.@CollectionProperty;if (a != null) { for (int ia = 0; ia < a.Count; ia++) { Write10_MyCollectionItem(@"MyCollectionItem", @"http://weblogs.asp.net/cazzu/", ((MyAssembly.MyCollectionItem)a[ia]), false, false); }}
本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
XMLSchema 模式與命名空間
注冊(cè)XML Schema到ORACLE XDB并對(duì)XML進(jìn)行驗(yàn)證
XSD schema xmns xsi
Vistual Studio自帶的xsd.exe工具,根據(jù)XML自動(dòng)生成XSD
圖形描述語(yǔ)言GraphML(5):擴(kuò)展 GraphML
xsd schema 語(yǔ)法
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服