| File: CodeDomFixup\ArrayOfXElementTypeHelper.cs | Web Access |
| Project: src\src\dotnet-svcutil\lib\src\dotnet-svcutil-lib.csproj (dotnet-svcutil-lib) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System; using Microsoft.CodeDom; using Microsoft.CodeDom.Compiler; using System.Collections.Generic; using System.Globalization; using System.Reflection; namespace Microsoft.Tools.ServiceModel.Svcutil { internal class ArrayOfXElementTypeHelper { private const string ArrayOfXElementTypeName = "ArrayOfXElement"; private static CodeTypeDeclaration s_arrayOfXElements = null; private static CodeTypeReference s_arrayOfXElementRef = null; private List<string> _addedToCodeCompileUnit = new List<string>(); private List<string> _needToAdd = new List<string>(); private const string xelementType = "System.Xml.Linq.XElement"; internal string SpecialNamespace = ""; private static bool s_isInternal = false; internal ArrayOfXElementTypeHelper(bool isInternal, CodeCompileUnit cu) { ArrayOfXElementTypeHelper.s_isInternal = isInternal; //ArrayOfXElement will be in the global namespace CodeNamespace targetNamespace = cu.Namespaces.Count > 0 ? cu.Namespaces[0] : new CodeNamespace(); SpecialNamespace = targetNamespace.Name; s_arrayOfXElements = CreateArrayOfXmlElementClass(targetNamespace); s_arrayOfXElementRef = new CodeTypeReference(GetUniqueClassName(targetNamespace)); } internal static CodeTypeDeclaration ArrayOfXElements { get { return s_arrayOfXElements; } } internal static CodeTypeReference ArrayOfXElementRef { get { return s_arrayOfXElementRef; } } internal void CheckToAdd(string namespaceToAdd) { if (!_needToAdd.Contains(namespaceToAdd)) { _needToAdd.Add(namespaceToAdd); } } internal static string GetUniqueClassName(CodeNamespace ns) { string uniqueName = ArrayOfXElementTypeName; Dictionary<string, CodeTypeDeclaration> nameTable = new Dictionary<string, CodeTypeDeclaration>(); foreach (CodeTypeDeclaration type in ns.Types) { if (!nameTable.ContainsKey(type.Name)) { nameTable.Add(type.Name, type); } } int i = 0; while (nameTable.ContainsKey(uniqueName)) { uniqueName = ArrayOfXElementTypeName + (++i).ToString(CultureInfo.InvariantCulture); } return uniqueName; } private static void AddGeneratedCodeAttribute(CodeTypeDeclaration codeType) { CodeAttributeDeclaration generatedCodeAttribute = new CodeAttributeDeclaration(new CodeTypeReference(typeof(GeneratedCodeAttribute))); AssemblyName assemblyName = typeof(ArrayOfXElementTypeHelper).GetTypeInfo().Assembly.GetName(); generatedCodeAttribute.Arguments.Add(new CodeAttributeArgument(new CodePrimitiveExpression(assemblyName.Name))); generatedCodeAttribute.Arguments.Add(new CodeAttributeArgument(new CodePrimitiveExpression(assemblyName.Version.ToString()))); codeType.CustomAttributes.Add(generatedCodeAttribute); } internal void AddToCompileUnit(CodeCompileUnit codeCompileUnit, string namespaceToAdd) { if (!_addedToCodeCompileUnit.Contains(namespaceToAdd) && _needToAdd.Contains(namespaceToAdd)) { //if it is special namespace and there is only one namespace, add the special type to the first ns because that's when -n is used if (codeCompileUnit.Namespaces.Count > 0 && namespaceToAdd.Equals(SpecialNamespace)) { _needToAdd.Remove(namespaceToAdd); namespaceToAdd = codeCompileUnit.Namespaces[0].Name; _needToAdd.Add(namespaceToAdd); } foreach (CodeNamespace ns in codeCompileUnit.Namespaces) { if (namespaceToAdd.Equals(ns.Name)) { ns.Types.Add(ArrayOfXElements); _addedToCodeCompileUnit.Add(namespaceToAdd); break; } } } } internal static CodeTypeReference CreateTypeReference(string typeName, params string[] typeArguments) { CodeTypeReference[] typeRefArgs = new CodeTypeReference[typeArguments.Length]; for (int i = 0; i < typeArguments.Length; i++) { typeRefArgs[i] = new CodeTypeReference(typeArguments[i]); } return new CodeTypeReference(typeName, typeRefArgs); } private static CodeTypeDeclaration CreateArrayOfXmlElementClass(CodeNamespace ns) { CodeTypeDeclaration classToGen = new CodeTypeDeclaration(GetUniqueClassName(ns)); classToGen.IsClass = true; classToGen.IsPartial = true; classToGen.TypeAttributes = s_isInternal ? TypeAttributes.NotPublic : TypeAttributes.Public; CodeAttributeDeclaration xmlSchemaProviderAttribute = new CodeAttributeDeclaration(new CodeTypeReference(typeof(Microsoft.Xml.Serialization.XmlSchemaProviderAttribute)), new CodeAttributeArgument(new CodePrimitiveExpression(null)), new CodeAttributeArgument("IsAny", new CodePrimitiveExpression(true))); classToGen.CustomAttributes.Add(xmlSchemaProviderAttribute); classToGen.BaseTypes.Add(new CodeTypeReference(typeof(Object))); classToGen.BaseTypes.Add(new CodeTypeReference(typeof(Microsoft.Xml.Serialization.IXmlSerializable))); CodeConstructor ctor = new CodeConstructor(); ctor.Attributes = MemberAttributes.Public; classToGen.Members.Add(ctor); AddField(classToGen); AddProperty(classToGen); AddGetSchemaMethod(classToGen); AddWriteXml(classToGen); AddReadXml(classToGen); AddGeneratedCodeAttribute(classToGen); return classToGen; } private static void AddField(CodeTypeDeclaration classToGen) { CodeMemberField nodesField = new CodeMemberField(); nodesField.Attributes = MemberAttributes.Private; nodesField.Name = "nodesList"; CodeTypeReference listOfXElement = CreateTypeReference("System.Collections.Generic.List`1", xelementType); nodesField.Type = listOfXElement; nodesField.InitExpression = new CodeObjectCreateExpression(listOfXElement); classToGen.Members.Add(nodesField); } private static void AddProperty(CodeTypeDeclaration classToGen) { CodeMemberProperty nodesProperty = new CodeMemberProperty(); nodesProperty.Attributes = MemberAttributes.Public; nodesProperty.Name = "Nodes"; nodesProperty.HasGet = true; CodeTypeReference listOfXElement = CreateTypeReference("System.Collections.Generic.List`1", xelementType); nodesProperty.Type = listOfXElement; nodesProperty.GetStatements.Add(new CodeMethodReturnStatement( new CodeFieldReferenceExpression( new CodeThisReferenceExpression(), "nodesList"))); classToGen.Members.Add(nodesProperty); } private static void AddGetSchemaMethod(CodeTypeDeclaration classToGen) { CodeMemberMethod getSchemaMethod = new CodeMemberMethod(); getSchemaMethod.Attributes = MemberAttributes.Public; getSchemaMethod.Name = "GetSchema"; getSchemaMethod.ImplementationTypes.Add(classToGen.BaseTypes[1]); getSchemaMethod.ReturnType = new CodeTypeReference(typeof(Microsoft.Xml.Schema.XmlSchema)); CodeThrowExceptionStatement throwException = new CodeThrowExceptionStatement( new CodeObjectCreateExpression( new CodeTypeReference(typeof(NotImplementedException)), new CodeExpression[] { })); getSchemaMethod.Statements.Add(throwException); classToGen.Members.Add(getSchemaMethod); } private static void AddWriteXml(CodeTypeDeclaration classToGen) { CodeMemberMethod writeXml = new CodeMemberMethod(); writeXml.Name = "WriteXml"; writeXml.Attributes = MemberAttributes.Public; writeXml.ImplementationTypes.Add(classToGen.BaseTypes[1]); writeXml.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(Microsoft.Xml.XmlWriter)), "writer")); CodeVariableDeclarationStatement enumeratorDec = new CodeVariableDeclarationStatement( CreateTypeReference("System.Collections.Generic.IEnumerator`1", xelementType), "e", new CodeMethodInvokeExpression(new CodeVariableReferenceExpression("nodesList"), "GetEnumerator")); writeXml.Statements.Add(enumeratorDec); CodeVariableReferenceExpression eRef = new CodeVariableReferenceExpression("e"); CodePropertyReferenceExpression eCurrent = new CodePropertyReferenceExpression(eRef, "Current"); CodeCastExpression iXmlSerCast = new CodeCastExpression(new CodeTypeReference(typeof(Microsoft.Xml.Serialization.IXmlSerializable)), eCurrent); CodeMethodInvokeExpression codeWrite = new CodeMethodInvokeExpression(iXmlSerCast, "WriteXml", new CodeVariableReferenceExpression("writer")); CodeIterationStatement codeFor = new CodeIterationStatement(); codeFor.TestExpression = new CodeMethodInvokeExpression(new CodeMethodReferenceExpression(new CodeVariableReferenceExpression("e"), "MoveNext")); codeFor.Statements.Add(codeWrite); codeFor.IncrementStatement = new CodeSnippetStatement(""); codeFor.InitStatement = new CodeSnippetStatement(""); writeXml.Statements.Add(codeFor); classToGen.Members.Add(writeXml); } private static void AddReadXml(CodeTypeDeclaration classToGen) { CodeMemberMethod readXml = new CodeMemberMethod(); readXml.Name = "ReadXml"; readXml.Attributes = MemberAttributes.Public; readXml.ImplementationTypes.Add(classToGen.BaseTypes[1]); readXml.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(Microsoft.Xml.XmlReader)), "reader")); CodeVariableReferenceExpression reader = new CodeVariableReferenceExpression("reader"); CodePropertyReferenceExpression readerNodeType = new CodePropertyReferenceExpression(reader, "NodeType"); CodeTypeReferenceExpression xmlNodeType = new CodeTypeReferenceExpression(typeof(Microsoft.Xml.XmlNodeType)); CodePropertyReferenceExpression xmlNodeTypeEndElement = new CodePropertyReferenceExpression(xmlNodeType, "EndElement"); CodeBinaryOperatorExpression notEq = new CodeBinaryOperatorExpression(readerNodeType, CodeBinaryOperatorType.IdentityInequality, xmlNodeTypeEndElement); CodeIterationStatement codeFor = new CodeIterationStatement(); codeFor.TestExpression = notEq; codeFor.IncrementStatement = new CodeSnippetStatement(""); codeFor.InitStatement = new CodeSnippetStatement(""); CodePropertyReferenceExpression xmlNodeTypeElement = new CodePropertyReferenceExpression(xmlNodeType, "Element"); CodeBinaryOperatorExpression eQElement = new CodeBinaryOperatorExpression(readerNodeType, CodeBinaryOperatorType.ValueEquality, xmlNodeTypeElement); CodeVariableDeclarationStatement element = new CodeVariableDeclarationStatement( new CodeTypeReference(xelementType), "elem", new CodeObjectCreateExpression(new CodeTypeReference(xelementType), new CodePrimitiveExpression("default"))); CodeCastExpression iXmlSerCast = new CodeCastExpression(new CodeTypeReference(typeof(Microsoft.Xml.Serialization.IXmlSerializable)), new CodeVariableReferenceExpression("elem")); CodeMethodInvokeExpression codeRead = new CodeMethodInvokeExpression(iXmlSerCast, "ReadXml", new CodeVariableReferenceExpression("reader")); CodeMethodInvokeExpression addNode = new CodeMethodInvokeExpression( new CodeMethodReferenceExpression(new CodeVariableReferenceExpression("Nodes"), "Add"), new CodeVariableReferenceExpression("elem")); CodeConditionStatement codeIfElse = new CodeConditionStatement(eQElement); codeIfElse.TrueStatements.Add(element); codeIfElse.TrueStatements.Add(codeRead); codeIfElse.TrueStatements.Add(addNode); CodeMethodInvokeExpression skip = new CodeMethodInvokeExpression(new CodeMethodReferenceExpression(new CodeVariableReferenceExpression("reader"), "Skip")); codeIfElse.FalseStatements.Add(skip); codeFor.Statements.Add(codeIfElse); readXml.Statements.Add(codeFor); classToGen.Members.Add(readXml); } } }