The Labs \ Source Viewer \ SSCLI \ System.Xml.Serialization \ CodeExporter

  1. //------------------------------------------------------------------------------
  2. // <copyright file="CodeExporter.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. // <owner current="true" primary="true">ElenaK</owner>
  15. //------------------------------------------------------------------------------
  16. namespace System.Xml.Serialization
  17. {
  18.    
  19.     using System;
  20.     using System.Collections;
  21.     using System.IO;
  22.     using System.ComponentModel;
  23.     using System.Xml.Schema;
  24.     using System.CodeDom;
  25.     using System.CodeDom.Compiler;
  26.     using System.Reflection;
  27.     using System.Globalization;
  28.     using System.Diagnostics;
  29.     using System.Security.Permissions;
  30.    
  31.     /// <include file='doc\CodeExporter.uex' path='docs/doc[@for="CodeExporter"]/*' />
  32.     ///<internalonly/>
  33.     /// <devdoc>
  34.     /// <para>[To be supplied.]</para>
  35.     /// </devdoc>
  36.     [PermissionSet(SecurityAction.InheritanceDemand, Name = "FullTrust")]
  37.     public abstract class CodeExporter
  38.     {
  39.         Hashtable exportedMappings;
  40.         Hashtable exportedClasses;
  41.         // TypeMapping -> CodeTypeDeclaration
  42.         CodeNamespace codeNamespace;
  43.         CodeCompileUnit codeCompileUnit;
  44.         bool rootExported;
  45.         TypeScope scope;
  46.         CodeAttributeDeclarationCollection includeMetadata = new CodeAttributeDeclarationCollection();
  47.         CodeGenerationOptions options;
  48.         CodeDomProvider codeProvider;
  49.         CodeAttributeDeclaration generatedCodeAttribute;
  50.        
  51.         internal CodeExporter(CodeNamespace codeNamespace, CodeCompileUnit codeCompileUnit, CodeDomProvider codeProvider, CodeGenerationOptions options, Hashtable exportedMappings)
  52.         {
  53.             if (codeNamespace != null)
  54.                 CodeGenerator.ValidateIdentifiers(codeNamespace);
  55.             this.codeNamespace = codeNamespace;
  56.             if (codeCompileUnit != null) {
  57.                 if (!codeCompileUnit.ReferencedAssemblies.Contains("System.dll"))
  58.                     codeCompileUnit.ReferencedAssemblies.Add("System.dll");
  59.                 if (!codeCompileUnit.ReferencedAssemblies.Contains("System.Xml.dll"))
  60.                     codeCompileUnit.ReferencedAssemblies.Add("System.Xml.dll");
  61.             }
  62.             this.codeCompileUnit = codeCompileUnit;
  63.             this.options = options;
  64.             this.exportedMappings = exportedMappings;
  65.             this.codeProvider = codeProvider;
  66.         }
  67.        
  68.         internal CodeCompileUnit CodeCompileUnit {
  69.             get { return codeCompileUnit; }
  70.         }
  71.        
  72.         internal CodeNamespace CodeNamespace {
  73.             get {
  74.                 if (codeNamespace == null)
  75.                     codeNamespace = new CodeNamespace();
  76.                 return codeNamespace;
  77.             }
  78.         }
  79.         internal CodeDomProvider CodeProvider {
  80.             get {
  81.                 if (codeProvider == null)
  82.                     codeProvider = new Microsoft.CSharp.CSharpCodeProvider();
  83.                 return codeProvider;
  84.             }
  85.         }
  86.        
  87.         internal Hashtable ExportedClasses {
  88.             get {
  89.                 if (exportedClasses == null)
  90.                     exportedClasses = new Hashtable();
  91.                 return exportedClasses;
  92.             }
  93.         }
  94.        
  95.         internal Hashtable ExportedMappings {
  96.             get {
  97.                 if (exportedMappings == null)
  98.                     exportedMappings = new Hashtable();
  99.                 return exportedMappings;
  100.             }
  101.         }
  102.        
  103.         internal bool GenerateProperties {
  104.             get { return (options & CodeGenerationOptions.GenerateProperties) != 0; }
  105.         }
  106.        
  107.         internal CodeAttributeDeclaration GeneratedCodeAttribute {
  108.             get {
  109.                 if (generatedCodeAttribute == null) {
  110.                     CodeAttributeDeclaration decl = new CodeAttributeDeclaration(typeof(GeneratedCodeAttribute).FullName);
  111.                     Assembly a = Assembly.GetEntryAssembly();
  112.                     if (a == null) {
  113.                         a = Assembly.GetExecutingAssembly();
  114.                         if (a == null) {
  115.                             a = typeof(CodeExporter).Assembly;
  116.                         }
  117.                     }
  118.                     AssemblyName assemblyName = a.GetName();
  119.                     decl.Arguments.Add(new CodeAttributeArgument(new CodePrimitiveExpression(assemblyName.Name)));
  120.                     string version = GetProductVersion(a);
  121.                     decl.Arguments.Add(new CodeAttributeArgument(new CodePrimitiveExpression(version == null ? assemblyName.Version.ToString() : version)));
  122.                     generatedCodeAttribute = decl;
  123.                 }
  124.                 return generatedCodeAttribute;
  125.             }
  126.         }
  127.        
  128.         static internal CodeAttributeDeclaration FindAttributeDeclaration(Type type, CodeAttributeDeclarationCollection metadata)
  129.         {
  130.             foreach (CodeAttributeDeclaration attribute in metadata) {
  131.                 if (attribute.Name == type.FullName || attribute.Name == type.Name) {
  132.                     return attribute;
  133.                 }
  134.             }
  135.             return null;
  136.         }
  137.        
  138.         private static string GetProductVersion(Assembly assembly)
  139.         {
  140.             object[] attributes = assembly.GetCustomAttributes(true);
  141.             for (int i = 0; i < attributes.Length; i++) {
  142.                 if (attributes[i] is AssemblyInformationalVersionAttribute) {
  143.                     AssemblyInformationalVersionAttribute version = (AssemblyInformationalVersionAttribute)attributes[i];
  144.                     return version.InformationalVersion;
  145.                 }
  146.             }
  147.             return null;
  148.         }
  149.        
  150.         /// <include file='doc\XmlCodeExporter.uex' path='docs/doc[@for="XmlCodeExporter.IncludeMetadata"]/*' />
  151.         /// <devdoc>
  152.         /// <para>[To be supplied.]</para>
  153.         /// </devdoc>
  154.         public CodeAttributeDeclarationCollection IncludeMetadata {
  155.             get { return includeMetadata; }
  156.         }
  157.        
  158.         internal TypeScope Scope {
  159.             get { return scope; }
  160.         }
  161.        
  162.         internal void CheckScope(TypeScope scope)
  163.         {
  164.             if (this.scope == null) {
  165.                 this.scope = scope;
  166.             }
  167.             else if (this.scope != scope) {
  168.                 throw new InvalidOperationException(Res.GetString(Res.XmlMappingsScopeMismatch));
  169.             }
  170.         }
  171.        
  172.         internal abstract void ExportDerivedStructs(StructMapping mapping);
  173.         internal abstract void EnsureTypesExported(Accessor[] accessors, string ns);
  174.        
  175.         static internal void AddWarningComment(CodeCommentStatementCollection comments, string text)
  176.         {
  177.             comments.Add(new CodeCommentStatement(Res.GetString(Res.XmlCodegenWarningDetails, text), false));
  178.         }
  179.        
  180.         internal void ExportRoot(StructMapping mapping, Type includeType)
  181.         {
  182.             if (!rootExported) {
  183.                 rootExported = true;
  184.                 ExportDerivedStructs(mapping);
  185.                
  186.                 for (StructMapping derived = mapping.DerivedMappings; derived != null; derived = derived.NextDerivedMapping) {
  187.                     if (!derived.ReferencedByElement && derived.IncludeInSchema && !derived.IsAnonymousType) {
  188.                         CodeAttributeDeclaration include = new CodeAttributeDeclaration(includeType.FullName);
  189.                         include.Arguments.Add(new CodeAttributeArgument(new CodeTypeOfExpression(derived.TypeDesc.FullName)));
  190.                         includeMetadata.Add(include);
  191.                     }
  192.                 }
  193.                 Hashtable typesIncluded = new Hashtable();
  194.                 foreach (TypeMapping m in Scope.TypeMappings) {
  195.                     if (m is ArrayMapping) {
  196.                         ArrayMapping arrayMapping = (ArrayMapping)m;
  197.                         if (ShouldInclude(arrayMapping) && !typesIncluded.Contains(arrayMapping.TypeDesc.FullName)) {
  198.                             CodeAttributeDeclaration include = new CodeAttributeDeclaration(includeType.FullName);
  199.                             include.Arguments.Add(new CodeAttributeArgument(new CodeTypeOfExpression(arrayMapping.TypeDesc.FullName)));
  200.                             includeMetadata.Add(include);
  201.                             typesIncluded.Add(arrayMapping.TypeDesc.FullName, string.Empty);
  202.                             EnsureTypesExported(arrayMapping.Elements, arrayMapping.Namespace);
  203.                         }
  204.                     }
  205.                 }
  206.             }
  207.         }
  208.        
  209.         private static bool ShouldInclude(ArrayMapping arrayMapping)
  210.         {
  211.             if (arrayMapping.ReferencedByElement)
  212.                 return false;
  213.             if (arrayMapping.Next != null)
  214.                 return false;
  215.             if (arrayMapping.Elements.Length == 1) {
  216.                 TypeKind kind = arrayMapping.Elements[0].Mapping.TypeDesc.Kind;
  217.                 if (kind == TypeKind.Node)
  218.                     return false;
  219.             }
  220.            
  221.             for (int i = 0; i < arrayMapping.Elements.Length; i++) {
  222.                 if (arrayMapping.Elements[i].Name != arrayMapping.Elements[i].Mapping.DefaultElementName) {
  223.                     // in the case we need custom attributes to serialize an array instance, we cannot include arrau mapping without explicit reference.
  224.                     return false;
  225.                 }
  226.             }
  227.             return true;
  228.         }
  229.        
  230.         internal CodeTypeDeclaration ExportEnum(EnumMapping mapping, Type type)
  231.         {
  232.             CodeTypeDeclaration codeClass = new CodeTypeDeclaration(mapping.TypeDesc.Name);
  233.            
  234.             codeClass.Comments.Add(new CodeCommentStatement(Res.GetString(Res.XmlRemarks), true));
  235.             codeClass.IsEnum = true;
  236.             if (mapping.IsFlags && mapping.Constants.Length > 31) {
  237.                 codeClass.BaseTypes.Add(new CodeTypeReference(typeof(long)));
  238.             }
  239.             codeClass.TypeAttributes |= TypeAttributes.Public;
  240.             CodeNamespace.Types.Add(codeClass);
  241.             for (int i = 0; i < mapping.Constants.Length; i++) {
  242.                 ExportConstant(codeClass, mapping.Constants[i], type, mapping.IsFlags, 1l << i);
  243.             }
  244.             if (mapping.IsFlags) {
  245.                 // Add [FlagsAttribute]
  246.                 CodeAttributeDeclaration flags = new CodeAttributeDeclaration(typeof(FlagsAttribute).FullName);
  247.                 codeClass.CustomAttributes.Add(flags);
  248.             }
  249.             CodeGenerator.ValidateIdentifiers(codeClass);
  250.             return codeClass;
  251.         }
  252.        
  253.         internal void AddTypeMetadata(CodeAttributeDeclarationCollection metadata, Type type, string defaultName, string name, string ns, bool includeInSchema)
  254.         {
  255.             CodeAttributeDeclaration attribute = new CodeAttributeDeclaration(type.FullName);
  256.             if (name == null || name.Length == 0) {
  257.                 attribute.Arguments.Add(new CodeAttributeArgument("AnonymousType", new CodePrimitiveExpression(true)));
  258.             }
  259.             else {
  260.                 if (defaultName != name) {
  261.                     attribute.Arguments.Add(new CodeAttributeArgument("TypeName", new CodePrimitiveExpression(name)));
  262.                 }
  263.                 if (ns != null && ns.Length != 0) {
  264.                     attribute.Arguments.Add(new CodeAttributeArgument("Namespace", new CodePrimitiveExpression(ns)));
  265.                 }
  266.             }
  267.             if (!includeInSchema) {
  268.                 attribute.Arguments.Add(new CodeAttributeArgument("IncludeInSchema", new CodePrimitiveExpression(false)));
  269.             }
  270.             if (attribute.Arguments.Count > 0) {
  271.                 metadata.Add(attribute);
  272.             }
  273.         }
  274.        
  275.         static internal void AddIncludeMetadata(CodeAttributeDeclarationCollection metadata, StructMapping mapping, Type type)
  276.         {
  277.             if (mapping.IsAnonymousType)
  278.                 return;
  279.             for (StructMapping derived = mapping.DerivedMappings; derived != null; derived = derived.NextDerivedMapping) {
  280.                 CodeAttributeDeclaration attribute = new CodeAttributeDeclaration(type.FullName);
  281.                 attribute.Arguments.Add(new CodeAttributeArgument(new CodeTypeOfExpression(derived.TypeDesc.FullName)));
  282.                 metadata.Add(attribute);
  283.                 AddIncludeMetadata(metadata, derived, type);
  284.             }
  285.         }
  286.        
  287.         static internal void ExportConstant(CodeTypeDeclaration codeClass, ConstantMapping constant, Type type, bool init, long enumValue)
  288.         {
  289.             CodeMemberField field = new CodeMemberField(typeof(int).FullName, constant.Name);
  290.             field.Comments.Add(new CodeCommentStatement(Res.GetString(Res.XmlRemarks), true));
  291.             if (init)
  292.                 field.InitExpression = new CodePrimitiveExpression(enumValue);
  293.             codeClass.Members.Add(field);
  294.             if (constant.XmlName != constant.Name) {
  295.                 CodeAttributeDeclaration attribute = new CodeAttributeDeclaration(type.FullName);
  296.                 attribute.Arguments.Add(new CodeAttributeArgument(new CodePrimitiveExpression(constant.XmlName)));
  297.                 field.CustomAttributes.Add(attribute);
  298.             }
  299.         }
  300.        
  301.         static internal object PromoteType(Type type, object value)
  302.         {
  303.             if (type == typeof(sbyte)) {
  304.                 return ((IConvertible)value).ToInt16(null);
  305.             }
  306.             else if (type == typeof(UInt16)) {
  307.                 return ((IConvertible)value).ToInt32(null);
  308.             }
  309.             else if (type == typeof(UInt32)) {
  310.                 return ((IConvertible)value).ToInt64(null);
  311.             }
  312.             else if (type == typeof(UInt64)) {
  313.                 return ((IConvertible)value).ToDecimal(null);
  314.             }
  315.             else {
  316.                 return value;
  317.             }
  318.         }
  319.        
  320.         internal CodeMemberProperty CreatePropertyDeclaration(CodeMemberField field, string name, string typeName)
  321.         {
  322.             CodeMemberProperty prop = new CodeMemberProperty();
  323.             prop.Type = new CodeTypeReference(typeName);
  324.             prop.Name = name;
  325.             prop.Attributes = (prop.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Public;
  326.            
  327.             //add get
  328.             CodeMethodReturnStatement ret = new CodeMethodReturnStatement();
  329.             ret.Expression = new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), field.Name);
  330.             prop.GetStatements.Add(ret);
  331.            
  332.             CodeAssignStatement propertySet = new CodeAssignStatement();
  333.             CodeExpression left = new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), field.Name);
  334.             CodeExpression right = new CodePropertySetValueReferenceExpression();
  335.             propertySet.Left = left;
  336.             propertySet.Right = right;
  337.            
  338.             if (EnableDataBinding) {
  339.                 CodeConditionStatement ifStatement = new CodeConditionStatement();
  340.                 ifStatement.Condition = new CodeBinaryOperatorExpression(left, CodeBinaryOperatorType.IdentityInequality, right);
  341.                 ifStatement.TrueStatements.Add(propertySet);
  342.                 ifStatement.TrueStatements.Add(new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), RaisePropertyChangedEventMethod.Name, new CodePrimitiveExpression(name)));
  343.                 prop.SetStatements.Add(ifStatement);
  344.             }
  345.             else
  346.                 prop.SetStatements.Add(propertySet);
  347.            
  348.             return prop;
  349.         }
  350.        
  351.         static internal string MakeFieldName(string name)
  352.         {
  353.             return CodeIdentifier.MakeCamel(name) + "Field";
  354.         }
  355.        
  356.         internal void AddPropertyChangedNotifier(CodeTypeDeclaration codeClass)
  357.         {
  358.             if (EnableDataBinding && codeClass != null) {
  359.                 if (codeClass.BaseTypes.Count == 0) {
  360.                     codeClass.BaseTypes.Add(typeof(object));
  361.                 }
  362.                 codeClass.BaseTypes.Add(new CodeTypeReference(typeof(System.ComponentModel.INotifyPropertyChanged)));
  363.                 codeClass.Members.Add(PropertyChangedEvent);
  364.                 codeClass.Members.Add(RaisePropertyChangedEventMethod);
  365.             }
  366.         }
  367.        
  368.         bool EnableDataBinding {
  369.             get { return (options & CodeGenerationOptions.EnableDataBinding) != 0; }
  370.         }
  371.        
  372.         static internal CodeMemberMethod RaisePropertyChangedEventMethod {
  373.             get {
  374.                 CodeMemberMethod raisePropertyChangedEventMethod = new CodeMemberMethod();
  375.                 raisePropertyChangedEventMethod.Name = "RaisePropertyChanged";
  376.                 raisePropertyChangedEventMethod.Attributes = MemberAttributes.Family | MemberAttributes.Final;
  377.                 CodeArgumentReferenceExpression propertyName = new CodeArgumentReferenceExpression("propertyName");
  378.                 raisePropertyChangedEventMethod.Parameters.Add(new CodeParameterDeclarationExpression(typeof(string), propertyName.ParameterName));
  379.                 CodeVariableReferenceExpression propertyChanged = new CodeVariableReferenceExpression("propertyChanged");
  380.                 raisePropertyChangedEventMethod.Statements.Add(new CodeVariableDeclarationStatement(typeof(PropertyChangedEventHandler), propertyChanged.VariableName, new CodeEventReferenceExpression(new CodeThisReferenceExpression(), PropertyChangedEvent.Name)));
  381.                 CodeConditionStatement ifStatement = new CodeConditionStatement(new CodeBinaryOperatorExpression(propertyChanged, CodeBinaryOperatorType.IdentityInequality, new CodePrimitiveExpression(null)));
  382.                 raisePropertyChangedEventMethod.Statements.Add(ifStatement);
  383.                 ifStatement.TrueStatements.Add(new CodeDelegateInvokeExpression(propertyChanged, new CodeThisReferenceExpression(), new CodeObjectCreateExpression(typeof(PropertyChangedEventArgs), propertyName)));
  384.                 return raisePropertyChangedEventMethod;
  385.             }
  386.         }
  387.        
  388.         static internal CodeMemberEvent PropertyChangedEvent {
  389.             get {
  390.                 CodeMemberEvent propertyChangedEvent = new CodeMemberEvent();
  391.                 propertyChangedEvent.Attributes = MemberAttributes.Public;
  392.                 propertyChangedEvent.Name = "PropertyChanged";
  393.                 propertyChangedEvent.Type = new CodeTypeReference(typeof(PropertyChangedEventHandler));
  394.                 propertyChangedEvent.ImplementationTypes.Add(typeof(System.ComponentModel.INotifyPropertyChanged));
  395.                 return propertyChangedEvent;
  396.             }
  397.         }
  398.        
  399.     }
  400. }

Developer Fusion