new codeassignstatement(
new codefieldreferenceexpression(
new codethisreferenceexpression(), member.name ),
new codeargumentreferenceexpression( "value" ) ) );
最后,我们只需向该类型中添加新的属性:
type.members.add( prop );
}
好了,先前的架构通过该工具生成以下代码:
/// <remarks/> [system.xml.serialization.xmlrootattribute(namespace="", isnullable=false)] public class publisher { /// <remarks/> public string pub_id;
向该架构添加相应的扩展以后:
<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> ...
该架构现在将生成:
///
[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;
}
}
使用集合而不是数组
对于任何比较像样的读写(具有 get 和 set 属性)对象模型而言,要使其可供程序员方便地使用,它的多值属性都应该基于集合,而不是基于数组。这样做会使修改值和操纵对象图变得更为容易。通常的方法涉及到从 collectionbase 派生一个新的类型化集合类。
在将更改提交给 codedom 之前,xmlserializer 支持必须对集合进行检查。在分析和反射要序列化的类型的类的内部深处,有一个名为 typescope 的内部类。typescope 负责确保生成序列化代码。它包含一个有趣的方法,名为 importtypedesc,该方法执行大多数检查工作并且为支持的类型生成信息。在这里,我们找到了对 ixmlserializable(它检查其成员中的安全特性)、数组(必须具有等于 1 的秩)、enums、xmlnode、xmlattribute 和 xmlelement 等的特殊支持。
尤其是对集合而言,导入方法检查实现 icollection 的类型,该类型必须满足下列规则:
• 必须具有一个 add 方法,该方法不是由该接口定义的,因为它通常是为该集合将要容纳的专用类型而创建的。
• 不得通过该集合实现 idictionary。
• 必须具有一个默认成员(即一个索引器)并且该成员具有一个类型为 system.int32 (c# int) 的参数。系统将在所有类型层次结构中搜索这样的成员。
• 在 add、count 和索引器中不能有任何安全特性。
在验证上述信息以后,生成的派生自 xmlserializationwriter 的专用类在为我们的类型编写 xml 输出时,将使用 count 属性进行迭代,而不使用基于数组的属性的 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); }}
请注意,在给定对索引器的上一次检查之后,对集合和数组的索引访问是相同的,所以此处没有进行更改。
相应的派生自 xmlserializationreader 的类使用类型化的 add 方法来填充集合:
myassembly.mycollection a_2 = (myassembly.mycollection)o.@collectionproperty;
...
while (reader.nodetype != system.xml.xmlnodetype.endelement)
{
if (reader.nodetype == system.xml.xmlnodetype.element)
{
if (((object) reader.localname == (object)id8_mycollectionitem &&
(object) reader.namespaceuri == (object)id9_httpweblogsaspnetcazzu))
{
if ((object)(a_2) == null)
reader.skip();
else
a_2.add(read10_mycollectionitem(false, true));
}
...
上面显示的读方法返回集合所期望的适当类型:
myassembly.mycollectionitem read1_mycollectionitem(bool isnullable,
bool checktype)
既然已经检验了 xmlserializer 能够支持和正确处理基于集合的属性,那么将所有数组更改为相应的强类型集合就是安全的。
可以将这一新的扩展设计为在上一个扩展之前或之后运行。其中的差别是明显的,因为迭代将分别从字段更改到新的属性。为了使该扩展独立于上一个扩展,我将对其进行编码以针对字段工作。不过,请注意,如果将其配置为在 fieldstopropertiesextension“之后”运行,则该代码将是不正确的。
让我们首先分析将生成自定义集合的方法。该集合应如下所示:
public class publishercollection : collectionbase
{
public int add(publisher value)
{
return base.innerlist.add(value);
}
public publisher this[int idx]
{
get { return (publisher) base.innerlist[idx]; }
set { base.innerlist[idx] = value; }
}
}
用于生成该类型化集合的代码为:
public codetypedeclaration getcollection( codetypereference fortype )