#region Disclaimer / License // Copyright (C) 2009, Kenneth Skovhede // http://www.hexad.dk, opensource@hexad.dk // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // #endregion using System; using System.CodeDom; using System.Collections; using System.Xml.Schema; namespace XsdGenerator.Extensions { /// /// Converts array-based properties into collection-based ones, and /// creates a typed inherited class for it. /// public class ArraysToCollectionsExtension : ICodeExtension { #region ICodeExtension Members 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 ); // Change field type to collection. field.Type = new CodeTypeReference( col.Name ); code.Types.Add( col ); } } } } } #endregion 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; } } }