(5)具体实施方式
本发明延及用于串行化具有自定义对象类型和串行化格式的用户界面对象的方法、系统和计算机程序产品。本发明的实施例可包括一个或多个专用和/或一个或多个通用计算机,包括各类计算机硬件,如后文所详细描述的。
图2所示是依照本发明的示例串行化管理器200。串行化管理器200包括具有标准串行化器224的标准串行化提供器220以及具有自定义串行化器244的自定义串行化提供器240。串行化器,如标准串行化器224或自定义串行化器244,能够将一个特定的对象类型或某一范围的对象类型串行化为特定的串行化格式的对象。一般而言,用不同的串行化器来将单个对象类型串行化为不同的串行化格式,在一些实现中,串行化提供器中存在独立的基类,提供不同的串行化格式。例如,如后文所详述的,XmlSerializer基类可以被用来将对象转换为可扩展标记语言(XML)。也可以用不同的串行化器和串行化提供器来将不同的对象类型串行化为单个串行化格式。
串行化提供器,如标准串行化提供器220和自定义串行化提供器240,标识用于特定对象类型和串行化格式的个别串行化器。例如,标准串行化提供器220可以标识标准串行化器224来将标准对象串行化为标准串行化格式。其它串行化器226可以用来将不同的对象格式串行化为同一标准串行化格式,或用来将标准对象串行化为不同的标准串行化格式。类似地,自定义串行化提供器240标识自定义串行化器244来将自定义对象串行化为自定义串行化格式,其它自定义串行化器246可以用来将不同的对象类型串行化为同一自定义串行化格式,或用来将同一自定义对象串行化为不同的自定义串行化格式。当然,串行化管理器200可以包含其它标准串行化提供器230以及其它自定义串行化提供器250。
串行化管理器200也提供串行化上下文信息210的信息存储,以供各种串行化器在串行化对象图形时使用。例如,具有多个对象的对象图形可能需要多个串行化器,每一串行化器生成其自己的输出。串行化管理器200根据需要为这些串行化器之间的通信提供方便。
在串行化管理器200内,可能使用元数据属性来将个别对象类型与特定串行化器相联系。例如,如后文详细描述的,对于不具有串行化器的对象类型或者为了替代现有的串行化器,可使用缺省串行化提供器属性来加载或安装串行化提供器。在串行化提供器内,如标准串行化提供器220或自定义串行化提供器240内,也可使用元数据属性来标识用于给定对象类型和串行化格式的合适的串行化器。
作为示例,考虑表III所示的XML格式。
表III
<TypeName><PropertyName>ValueString</PropertyName></TypeName> |
使用表IV所示的伪代码类XmlSerializer来串行化这一XML格式。
表IV
public abstract class XmlSerializer{public abstract string Serialize(IDesignerSerializerationManager m,object graph);} |
XmlSerializer是从更小的片断建立串的模块化类。例如,当传递具有整数值5的Int32数据类型时,XmlSerializer返回“5”。
表III中的XML格式建议两种基本的对象类型来串行化:具有特性的对象和能够转换为文本的对象。在大多数情况下,使用知道如何将该类转换成文本或XML标签的自定义串行化器来修饰每一个类消耗太多精力,并且当引入新的串行化格式时会导致维护问题。(为将现有的类串行化为新的串行化格式,在类中引入新属性,需要对该现有类的重编译。)串行化提供器通过一种回叫机制解决了这一问题,在回叫机制中,给予提供器机会来为给定类型提供串行化器。
对于当前的示例,对一组可用的类型作如下的限定:
1.如果该类型可以通过现有IConvertible接口转换为串,则标识StringXmlSerializer。
2.如果该类型无法转换为串,但是为公有类,并且具有空构造函数,则标识ObjectXmlSerializer。
3.如果不符合上述两条,则串行化提供器返回空,指示没有用于该对象的串行化器。(这一错误如何处理取决于进行调用的串行化器。)
以下表V中示出了实现上述标准的伪代码。
表V
internal class XmlSerializationProvider:IDesignerSerializationProvider{object GetSerializer(IDesignerSerializerationManager manager,object currentSerializer,Type objectType,Type serializerType){//Null values are given a null type by this providerif(objectType=null){return StringXmlSerializer.Instance;}if(typeof(IConvertible).IsSubclassOf(objectType)){return StringXmlSerializer.Instance;}if(objectType.GetConstructor(new object[])=null){return ObjectXmlSerializer.Instance;}return null;}} |
定义了串行化提供器之后,可以将其投入使用。尽管可以通过明确的添加方法将该串行化提供器给予串行化管理器200,然而这一方法需要有人来作出这一明确的调用。可选地,可以通过向串行化器基类添加Default Serialization ProviderAttribute来自动将串行化提供器添加到串行化管理器200。对于这一示例,该属性需要串行化提供器具有公有、空构造函数。因此,表IV的伪代码变为以下表VI所示。
表VI
[DefaultSerializationProvider(typeof(XmlSerializationProvider))]public abstract class XmlSerializer{} |
现在,不论何时向串行化管理器200寻求任一类型的XmlSerializer,如果缺省串行化提供器先前并未被添加,则它将被自动添加到串行化管理器。注意,这一属性是与串行化器而不是对象相关联,使得可以添加新的串行化格式而不需要重编译该类来使用该新的属性。
如上所述,示例XmlSerializer具有两个具体的串行化器类:StringXmlSerializer和ObjectXmlSerializer。表VII示出了StringXmlSerializer的伪代码实现。
表VII
internal class StringXmlSerializer:XmlSerializer{internal StringXmlSerializer Instance=new StringXmlSerializer();public override string Serialize(IDesignerSerializationManager m,object graph){if(graph=null) return string.Empty;IConvertible c=graph as IConvertible;if(c=null){//Rather than throwing excpetions,we can//add a list of errors to the serlialization |
//manager.m.ReportError(“Object is not IConvertible”);return null;}return c.ToString(CultureInfo.InvariantCulture);}} |
表VIII示出了ObjectXmlSerializer的伪代码实现,巡视了它所串行化的对象的公有特性。
表VIII
internal class ObjectXmlSerializer:XmlSerializer{internal ObjectXmlSerializer Instance=new ObjectXmlSerializer();public override string Serialize(IDesignerSerializationManager m,object graph){StringBuilder xml=new StringBuilder();xml.Append(“<”);xml.Append(graph.GetType().FullName);xml.Append(“>”);//Now,walk all the properties of the objectPropertyDescriptorCollection properties;Property p;properties=TypeDescriptor.GetProperties(graph); |
foreach(p in properties){if(!p.ShouldSerializeValue(graph)){continue;}object value=p.GetValue(graph);Type valueType=null;if(value!=null)valueType=value.GetType();//Get the serializer for this propertyXmlSerializer s=m.GetSerializer(valueType,typeof(XmlSerializer))as XmlSerializer;if(s=null){//No serializer means we must skip this//property.Tell the serialization manager//of the error.m.ReportError(string.Format(“Property{0}does not support XML serialization”,p.Name));continue;}//We have a valid property to writexml.Append(“<”);xml.Append(p.Name);xml.Append(“>”);xml.Append(s.Serialize(m,value); |
xml.Append(“</”);xml.Append(p.Name);xml.Append(“>”);}xml.Append(“</”);xml.Append(graph.GetType().FullName);xml.Append(“>”);return xml.ToString();}} |
注意,ObiectXmlSerializer对每一特性值调用其它串行化器。这至少具有两个优点。首先,它令ObjectXmlSerializer变得十分简单。其次,它对第三方类型提供了可扩充点。如果出现无法由这些串行化器的任一个写出的类型,则可以向该类型提供自定义串行化器。
表IX示出了上述串行化器对System.Drasing.Rectangle对象的示例使用,该对象具有空构造函数以及支持用于串转换的IConvertible的四个特性。在表IX中,创建了IDesignerSerializationManager的一个实例,即串行化管理器,并用来标识串行化器。然后所标识的串行化器串行化该对象。
表IX
Rectangler=new Rectangle(5,10,15,20);DesignerSerializationManager m=new DesignerSerializationManager();XmlSerializer x=(XmlSerializer)m.GetSerializer(r.GetType(),typeof(XmlSerializer);string xml=x.Serialize(m,r); |
表IX所示的示例生成表X所示的XML。
表X
<System.Drawing.Rectangle><X>5</X><Y>10</Y><Width>15</Width><Height>15</Height></System.Drawing.Rectangle> |
注意,该示例未包括任何XML缩进。然而,可以通过使用串行化管理器200的串行化上下文信息210简单地实现该缩进。每一串行化器层可以向包含当前缩进层的上下文栈添加对象,并且每一串行化器然后在栈内搜索该层上下文对象并使用它来提供合适的缩进。
串行化管理器200能够将对象串行化为不同的串行化格式。与上述XML串行化形成对比,下文的示例与代码生成格式有关。注意,依照本发明的示例实现,生成XML的串行化提供器和生成源代码的串行化提供器可能在串行化管理器200中共存。如参照图1所指示的,有多种方法来将对象串行化为源代码。例如,考虑具有单个OK按钮的窗体的情况。定义这一窗体的一个标准方法如下表XI所示。
表XI
public class Form 1:Form{private Button button 1;public Form1(){button1=new Button();button1.Location=new Point(100,100);button1.Text=“OK”;this.Controls.Add(button1);}} |
表XI的伪代码定义了“Form1”对象类型的新类。然而,让对象图形的根定义新类是任意的选择。该代码也可如表XII所示。
表XII
Form Form1=new Form();Button button1=new Button();button1.Location=new Point(100,100);button1.Text=“OK”;Form1.Controls.Add(button1); |
在两种情况下,所得是具有一个按钮的窗体。然而,对表XII中说明的代码片断,一般所有对象比对象图形的“根”更需要它,并且它对可视化设计器中的剪切/复制/粘贴以及撤销/重复操作更有用。对于这些操作,新对象的创建,至少最初的创建,可能是不必要且不合需要的,并因此需要一些额外的工作来避免它。在许多情况下,窗体可以仅以表XII所示的格式来简单表示。因此,在示例实现中,串行化管理器200具有两个不同的基本串行化类:CodeDomSerializer,仅创建并配置给定的对象;以及TypeCodeDomSerializer,定义新类。两个串行化器可以在串行化管理器200中共同存在。
以下表XIII示出了示例CodeDomSerializere类。
表XIII
public abstract class CodeDomSerializer{public abstract object Serialize(IDesignerSerializationManager m,object value);public virtual object SerializeProperty(IDesignerSerializationManager m,PropertyDescriptor p,object value);public abstract object Deserialize(IDesignerSerializationManager m,object state);} |
Serialize方法串行化给定的对象。其返回值取决于所需要的串行化类型,并可以是以下的任一种:
CodeExpression:如果对象可以串行化为简单的表达式,则返回CodeExpression。落入这一分类的原语如do类型可以在其构造函数中被创建及配置。
CodeStatementCollection:如果对象可以串行化为状态的集合,则返回CodeStatementCollection。需要构造且其一个或多个属性需要设定的复杂对象落入这一分类。
SerializeProperty方法串行化给定对象上的属性。使用这一串行化类型的一个模型如下:
1.向串行化管理器要求用于给定属性类型的串行化器。
2.在返回的串行化器上调用SerializeProperty。
3.将结果整合进自己的串行化数据中。
SerializeProperty的返回值取决于需要的串行化类型,并且可以是以下的任一种:
CodeStatement:如果属性可以串行化为单一状态,则返回CodeStatement。大多数属性落入这一分类。
CodeStatementCollection:如果属性能够串行化为状态的集合,则返回CodeStatementCollection。复杂的属性,如集合落入这一分类。
Deserilaize方法返回从给定的串行化数据配置的活对象。传入的作为“状态”的对象应当是与从先前的Serialize调用返回的对象的同一类型。
TypeCodeDomSerializer类执行与CodeDomSerializer相同的任务,但是通过这一个类来串行化对象定义了一个新类型。 以下表XIV示出了TypeCodeDomSerializer类的一个示例。
表XIV
public abstract TypeCodeDomSerializer{public abstract CodeTypeDeclaration Serialize(IDesignerSerializationManager m,object root,ICollection members);public abstract object Deserialize(IDesignerSerializationManager m,CodeTypeDeclaration typeDecl);} |
Serialize方法串行化给定根对象以及成员的可选集合来创建新类的定义。成员集合可以为零或空。如果它包含值,则这些值将被定义为该类型的成员变量。为方便起见,成员集合可以包含根对象。在这一情况下,根对象将不再被作为成员添加。Deserialize方法反串行化先前串行化的代码类型声明。它创建该类型声明的基本类型的实例,并通过设定属性与执行方法来对其进行配置。
本发明也可以按照包括功能性步骤和/或非功能性行动的方法来描述。以下是对可以在本发明的实践中执行的行动和步骤的描述。通常,功能性步骤按照所获得的结果来描述发明,而非功能性行动描述用于获得特定结果的更具体的行动。尽管功能性步骤和非功能性行动可能是以特定的顺序出现在说明书或权利要求书中的,然而本发明并不必局限于行动和/或步骤的任一特定顺序或组合。
图3示出了用于依照本发明来串行化用户界面对象的方法的示例行动和步骤。用于协调(310)一个或多个标准串行化提供器的步骤以及如所需要用于加载(310)一个或多个自定义串行化提供器的步骤可包括提供(312)串行化管理器的行动,其中,每一标准串行化提供器标识一个或多个用于标准对象类型或串行化格式的标准串行化器,每一自定义串行化提供器标识一个或多个用于可能未被所述一个或多个标准串行化提供器所覆盖的一个或多个自定义对象类型或串行化格式的自定义串行化器。
用于标识(320)用于特定串行化格式和包含特定对象类型的对象的对象图形的串行化器的步骤可包括向串行化管理器请求(322)串行化器的行动。用于串行化(330)的步骤可包括调用(332)串行化管理器返回的串行化器来串行化对象图形的行动。用于维护(未示出)上下文信息的步骤可包括在串行化管理器端储存上下文信息的行动(未示出)。用于以自定义串行化器替代(未示出)标准串行化器的步骤可包括提供(312)串行化管理器来加载一个或多个自定义串行化提供器的行动,其中,每一自定义串行化提供器标识一个或多个自定义串行化器。
自定义串行化器和串行化提供器可以被加载作为对请求串行化器的响应。要串行化的对象图形可包括多个相关对象。串行化器可生成对象图形的代码片断而不是类表示,作为剪切/复制/粘贴或撤销/重复操作的一部分。串行化器可串行化或反串行化对象图形,并可生成对象的活表示或存储器内表示、XML表示、源代码表示或其它表示。
本发明的范围内的实施例也包括用于含有或在其上储存计算机指令或数据结构的计算机可读媒质。这类计算机可读媒质可以是任一可由通用或专用计算机访问的可用媒质。作为示例而非局限,这类计算机可读媒质可包括RAM、ROM、EEPROM、CD-ROM或其它光盘存储、磁盘存储或其它磁存储设备、或其它可用来以计算机可执行指令或数据结构的形式携带或储存所期望的的程序代码方法并可由通用或专用计算机访问的任一媒质。当通过网络或另一通信连接(或者硬布线、或者无线、或硬布线和无线的组合)向计算机传输或提供信息时,计算机适当地将该连接视为计算机可读媒质。由此,任一这类连接适当地称为计算机可读媒质。上述的组合也应当包括在计算机可读媒质的范围内。计算机可执行指令包括,如,引发通用计算机、专用计算机或专用处理设备执行特定功能或功能组的指令和数据。
图4及以下讨论提供了对适于在其中实现本发明的计算环境的简要概括描述。尽管不需要,但本发明将在计算机可执行指令的一般语境下描述,计算机可执行指令如程序模块,由网络环境中的计算机执行。一般而言,程序模块包括例程、程序、对象、组件、数据结构等等,执行特定的任务或实现特定的抽象数据类型。计算机可执行指令、相关的数据结构以及程序模块表示了用于执行这里公开的方法的步骤的程序代码方法的示例。这一可执行指令或相关数据结构的特定顺序表示了用于实现在这类步骤中所描述的功能的相应行动的示例。
本领域的技术人员可以理解,本发明可以在具有多种类型计算机系统构造的网络计算环境中实践,包括个人计算机、手持式设备、多处理器系统、基于微处理器或可编程消费者电子设备、网络PC、小型机、大型机等等。本发明也可以在分布式计算环境中实践,其中,任务由通过通信网络连接(或者通过硬布线链路、或者通过无线链路、或通过硬布线或无线链路的组合)的本地和远程处理设备来执行。在分布式计算环境中,程序模块可以位于本地和远程存储器存储设备中。
参考图4,用于实现本发明的示例系统包括以常规计算机形式420的通用计算装置,包括处理单元421、系统存储器422以及将各类系统组件包括系统存储器422耦合至处理单元421的系统总线423。系统总线423可以是若干种总线结构类型的任一种,包括存储器总线或存储器控制器、外围总线以及使用各类总线结构的本地总线。系统存储器包括只读存储器(ROM)424和随机存取存储器(RAM)425。基本输入/输出系统(BIOS)426,包含如在启动时协助在计算机420内的元件之间传输信息的基本例程,可储存在ROM 424中。
计算机420也可包括用于对磁硬盘439进行读写的磁硬盘驱动器427、用于对可移动磁盘429进行读写的磁盘驱动器428以及用于对可移动光盘431如CD-ROM或其它光媒质进行读写的光盘驱动器430。磁硬盘驱动器427、磁盘驱动器428以及光盘驱动器430分别通过硬盘驱动器接口432、磁盘驱动器接口433和光盘驱动器接口434连接至系统总线423。驱动器及其相关的计算机可读媒质为计算机420提供了计算机可执行指令、数据结构、程序模块和其它数据的非易失存储。尽管这里描述的示例环境采用了磁硬盘439、可移动磁盘429以及可移动光盘431,然而也可以使用用于储存数据的其它类型的计算机可读媒质,包括盒式磁带、闪存卡、数字多功能盘、Bernoulli盒式磁盘、RAM、ROM等等。
包括一个或多个程序模块的程序代码方法可储存在硬盘439、磁盘429、光盘431、ROM 424或RAM 425中,包括操作系统435、一个或多个应用程序436、其它程序模块437以及程序数据438。用户可以通过键盘440、指向设备442或其它输入设备(未示出),如麦克风、操纵杆、游戏垫、圆盘式卫星天线、扫描仪等等向计算机420输入命令和信息。这些和其它输入设备通常通过耦合至系统总线423的串行端口接口446连接到处理单元421。可选地,输入设备也可以通过其它接口连接,如并行端口、游戏端口或通用串行总线(USB)。监视器447或另一显示设备也通过接口,如视频适配器448连接到系统总线423。除监视器之外,个人计算机通常包括其它外围输出设备(未示出),如扬声器和打印机。
计算机420可以在使用到一个或多个远程计算机,如远程计算机449a和449b的逻辑连接的网络化环境中操作。远程计算机449a和449b的每一个可以是另一个人计算机、服务器、路由器、网络PC、对等设备或其它公用网络节点,并通常包括许多或所有上述与计算机420相关的元件,尽管在图4中仅说明了存储器存储设备450a和450b及其关联的应用程序436a和436b。图4描述的逻辑连接包括局域网(LAN)451和广域网(WAN)452,这里示出作为示例而非局限。这类网络环境常见于办公室范围或企业范围计算机网络、内联网以及因特网。
当在局域网网络环境中使用时,计算机420通过网络接口或适配器453连接至局域网451。当在广域网网络环境中使用时,计算机420可包括调制解调器454、无线链路或其它装置,用于通过广域网452,如因特网建立通信。调制解调器454可以是内置或外置的,通过串行端口接口446连接至系统总线423。在网络化环境中,描述的与计算机420相关的程序模块或其部分可储存在远程存储器存储设备中。可以理解,示出的网络连接是示例性的,也可以使用通过广域网452建立通信的其它装置。
本发明可以在不脱离其精神或本质特征的情况下以其它特定形式来实施。描述的实施例在各个方面仅为说明性的而非限制。因此,本发明的范围由所附权利要求书来指明,而非之前的描述。所有处于权利要求的等效权利要求的范围和意思之内的变化都包含在其范围之内。