答案: 请注意,在给定对索引器的上一次检查之后,对集合和数组的索引访问是相同的,所以此处没有进行更改。
相应的派生自 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 )
{
CodeTypeDeclaration col = new CodeTypeDeclaration(
forType.BaseType + "Collection" );
col.BaseTypes.Add(typeof(CollectionBase));
col.Attributes = MemberAttributes.Final | MemberAttributes.Public;
// Add method
CodeMemberMethod add = new CodeMemberMethod();
add.Attributes = MemberAttributes.Final | MemberAttributes.Public;
add.Name = "Add";
add.ReturnType = new CodeTypeReference(typeof(int));
add.Parameters.Add( new CodeParameterDeclarationExpression (
forType, "value" ) );
// Generates: return base.InnerList.Add(value);
add.Statements.Add( new CodeMethodReturnStatement (
new CodeMethodInvokeExpression(
new CodePropertyReferenceExpression(
new CodeBaseReferenceExpression(), "InnerList"),
"Add",
new CodeExpression[]
{ new CodeArgumentReferenceExpression( "value" ) }
)
)
);
// Add to type.
col.Members.Add(add);
// Indexer property ('this')
CodeMemberProperty indexer = new CodeMemberProperty();
indexer.Attributes = MemberAttributes.Final | MemberAttributes.Public;
indexer.Name = "Item";
indexer.Type = forType;
indexer.Parameters.Add( new CodeParameterDeclarationExpression (
typeof( int ), "idx" ) );
indexer.HasGet = true;
indexer.HasSet = true;
// Generates: return (theType) base.InnerList[idx];
indexer.GetStatements.Add(
new CodeMethodReturnStatement (
new CodeCastExpression(
forType,
new CodeIndexerExpression(
new CodePropertyReferenceExpression(
new CodeBaseReferenceExpression(),
"InnerList"),
new CodeExpression[]
{ new CodeArgumentReferenceExpression( "idx" ) } )
)
)
);
// Generates: base.InnerList[idx] = value;
indexer.SetStatements.Add(
new CodeAssignStatement(
new CodeIndexerExpression(
new CodePropertyReferenceExpression(
new CodeBaseReferenceExpression(),
"InnerList"),
new CodeExpression[]
{ new CodeArgumentReferenceExpression("idx") }),
new CodeArgumentReferenceExpression( "value" )
)
);
// Add to type.
col.Members.Add(indexer);
return col;
}
此时,您应该考虑一个在对 CodeDom 进行编程时有用的技巧;看到这些似乎没完没了的 Statements.Add 代码行了吗?当然,我们可以将它们拆分为多个独立的行,每行创建一个临时变量以容纳该对象并将其传递给下一行。但这样只会使它们更加无穷无尽!那好,只要您能够习惯,那么下面的技巧会是一种将这些代码行拆分为多个部分的好方法:
要生成 CodeDom 嵌套语句,邻近的属性/索引器/方法访问通常是从右向左构建的。
实际上:要生成以下代码行:
base.InnerList[idx]
您应该从索引器表达式 [idx] 开始,接着是属性访问 InnerList,最后是对象引用基。这将生成下面的 CodeDom 嵌套语句:
CodeExpression st = new CodeIndexerExpression(
new CodePropertyReferenceExpression(
new CodeBaseReferenceExpression(),
"InnerList"
),
new CodeExpression[]
{ new CodeArgumentReferenceExpression( "idx" ) }
);
请注意,我从右向左创建语句,最后才完成适当的构造函数参数。用这种方式手动缩进和拆分代码行通常是一个好主意,这样可以更容易地看到各个对象构造函数在哪里结束以及哪些是它的参数。
最后,ICodeExtension.Process 方法实现涉及到对类型及其字段进行迭代,以查找基于数组的字段:
public class ArraysToCollectionsExtension : ICodeExtension
{
public void Process( CodeNamespace code, XmlSchema schema )
{
// Copy as we will be adding types.
CodeTypeDeclaration[] types =
new CodeTypeDeclaration[code.Types.Count];
code.Types.CopyTo( types, 0 );
foreach ( CodeTypeDeclaration type in types )
{
if ( type.IsClass || type.IsStruct )
{
foreach ( CodeTypeMember member in type.Members )
{
// Process fields only.
if ( member is CodeMemberField &&
( ( CodeMemberField )member ).Type.ArrayElementType != null )
{
CodeMemberField field = ( CodeMemberField ) member;
CodeTypeDeclaration col = GetCollection(
field.Type.ArrayElementType );
&nb
上一个:dotnet代码自动生成机的实现
下一个:.NET 框架中的 XML:在 .NET 框架中使用 XML 架构执行代码生成(2)