File: System\Runtime\Serialization\CodeExporter.cs
Project: ndp\cdf\src\WCF\Serialization\System.Runtime.Serialization.csproj (System.Runtime.Serialization)
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//------------------------------------------------------------
 
namespace System.Runtime.Serialization
{
    using System;
    using System.CodeDom;
    using System.CodeDom.Compiler;
    using System.Collections;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Globalization;
    using System.Reflection;
    using System.Security;
    using System.Text;
    using System.Xml;
    using System.Xml.Schema;
    using DataContractDictionary = System.Collections.Generic.Dictionary<System.Xml.XmlQualifiedName, DataContract>;
 
    class CodeExporter
    {
        DataContractSet dataContractSet;
        CodeCompileUnit codeCompileUnit;
        ImportOptions options;
        Dictionary<string, string> namespaces;
        Dictionary<string, string> clrNamespaces;
 
        [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - Static fields are marked SecurityCritical or readonly to prevent"
            + " data from being modified or leaked to other components in appdomain.")]
        static readonly string wildcardNamespaceMapping = "*";
 
        [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - Static fields are marked SecurityCritical or readonly to prevent"
            + " data from being modified or leaked to other components in appdomain.")]
        static readonly string typeNameFieldName = "typeName";
 
        [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - Static fields are marked SecurityCritical or readonly to prevent"
            + " data from being modified or leaked to other components in appdomain.")]
        static readonly object codeUserDataActualTypeKey = new object();
 
        [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - Static fields are marked SecurityCritical or readonly to prevent"
            + " data from being modified or leaked to other components in appdomain.")]
        static readonly object surrogateDataKey = typeof(IDataContractSurrogate);
        const int MaxIdentifierLength = 511;
 
        internal CodeExporter(DataContractSet dataContractSet, ImportOptions options, CodeCompileUnit codeCompileUnit)
        {
            this.dataContractSet = dataContractSet;
            this.codeCompileUnit = codeCompileUnit;
            AddReferencedAssembly(Assembly.GetExecutingAssembly());
            this.options = options;
            this.namespaces = new Dictionary<string, string>();
            this.clrNamespaces = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
 
            // Update namespace tables for DataContract(s) that are already processed
            foreach (KeyValuePair<XmlQualifiedName, DataContract> pair in dataContractSet)
            {
                DataContract dataContract = pair.Value;
                if (!(dataContract.IsBuiltInDataContract || dataContract is CollectionDataContract))
                {
                    ContractCodeDomInfo contractCodeDomInfo = GetContractCodeDomInfo(dataContract);
                    if (contractCodeDomInfo.IsProcessed && !contractCodeDomInfo.UsesWildcardNamespace)
                    {
                        string clrNamespace = contractCodeDomInfo.ClrNamespace;
                        if (clrNamespace != null && !this.clrNamespaces.ContainsKey(clrNamespace))
                        {
                            this.clrNamespaces.Add(clrNamespace, dataContract.StableName.Namespace);
                            this.namespaces.Add(dataContract.StableName.Namespace, clrNamespace);
                        }
                    }
                }
            }
 
            // Copy options.Namespaces to namespace tables
            if (this.options != null)
            {
                foreach (KeyValuePair<string, string> pair in options.Namespaces)
                {
                    string dataContractNamespace = pair.Key;
                    string clrNamespace = pair.Value;
                    if (clrNamespace == null)
                        clrNamespace = String.Empty;
 
                    string currentDataContractNamespace;
                    if (this.clrNamespaces.TryGetValue(clrNamespace, out currentDataContractNamespace))
                    {
                        if (dataContractNamespace != currentDataContractNamespace)
                            throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.CLRNamespaceMappedMultipleTimes, currentDataContractNamespace, dataContractNamespace, clrNamespace)));
                    }
                    else
                        this.clrNamespaces.Add(clrNamespace, dataContractNamespace);
 
                    string currentClrNamespace;
                    if (this.namespaces.TryGetValue(dataContractNamespace, out currentClrNamespace))
                    {
                        if (clrNamespace != currentClrNamespace)
                        {
                            this.namespaces.Remove(dataContractNamespace);
                            this.namespaces.Add(dataContractNamespace, clrNamespace);
                        }
                    }
                    else
                        this.namespaces.Add(dataContractNamespace, clrNamespace);
                }
            }
 
            // Update namespace tables for pre-existing namespaces in CodeCompileUnit
            foreach (CodeNamespace codeNS in codeCompileUnit.Namespaces)
            {
                string ns = codeNS.Name ?? string.Empty;
                if (!this.clrNamespaces.ContainsKey(ns))
                {
                    this.clrNamespaces.Add(ns, null);
                }
                if (ns.Length == 0)
                {
                    foreach (CodeTypeDeclaration codeTypeDecl in codeNS.Types)
                    {
                        AddGlobalTypeName(codeTypeDecl.Name);
                    }
                }
            }
 
        }
 
        void AddReferencedAssembly(Assembly assembly)
        {
            string assemblyName = System.IO.Path.GetFileName(assembly.Location);
            bool alreadyExisting = false;
            foreach (string existingName in this.codeCompileUnit.ReferencedAssemblies)
            {
                if (String.Compare(existingName, assemblyName, StringComparison.OrdinalIgnoreCase) == 0)
                {
                    alreadyExisting = true;
                    break;
                }
            }
            if (!alreadyExisting)
                this.codeCompileUnit.ReferencedAssemblies.Add(assemblyName);
 
        }
 
        bool GenerateSerializableTypes
        {
            get { return (options == null) ? false : options.GenerateSerializable; }
        }
 
        bool GenerateInternalTypes
        {
            get { return (options == null) ? false : options.GenerateInternal; }
        }
 
        bool EnableDataBinding
        {
            get { return (options == null) ? false : options.EnableDataBinding; }
        }
 
        CodeDomProvider CodeProvider
        {
            get { return (options == null) ? null : options.CodeProvider; }
        }
 
        bool SupportsDeclareEvents
        {
            [Fx.Tag.SecurityNote(Critical = "Critical because it calls the CodeProvider.Supports(..) method that has a LinkDemand.",
                Safe = "Safe because it doesn't leak security sensitive information.")]
            [SecuritySafeCritical]
            get { return (CodeProvider == null) ? true : CodeProvider.Supports(GeneratorSupport.DeclareEvents); }
        }
 
        bool SupportsDeclareValueTypes
        {
            [Fx.Tag.SecurityNote(Critical = "Critical because it calls the CodeProvider.Supports(..) method that has a LinkDemand.",
                Safe = "Safe because it doesn't leak security sensitive information.")]
            [SecuritySafeCritical]
            get { return (CodeProvider == null) ? true : CodeProvider.Supports(GeneratorSupport.DeclareValueTypes); }
        }
 
        bool SupportsGenericTypeReference
        {
            [Fx.Tag.SecurityNote(Critical = "Critical because it calls the CodeProvider.Supports(..) method that has a LinkDemand.",
                Safe = "Safe because it doesn't leak security sensitive information.")]
            [SecuritySafeCritical]
            get { return (CodeProvider == null) ? true : CodeProvider.Supports(GeneratorSupport.GenericTypeReference); }
        }
 
        bool SupportsAssemblyAttributes
        {
            [Fx.Tag.SecurityNote(Critical = "Critical because it calls the CodeProvider.Supports(..) method that has a LinkDemand.",
                Safe = "Safe because it doesn't leak security sensitive information.")]
            [SecuritySafeCritical]
            get { return (CodeProvider == null) ? true : CodeProvider.Supports(GeneratorSupport.AssemblyAttributes); }
        }
 
        bool SupportsPartialTypes
        {
            [Fx.Tag.SecurityNote(Critical = "Critical because it calls the CodeProvider.Supports(..) method that has a LinkDemand.",
                Safe = "Safe because it doesn't leak security sensitive information.")]
            [SecuritySafeCritical]
            get { return (CodeProvider == null) ? true : CodeProvider.Supports(GeneratorSupport.PartialTypes); }
        }
 
        bool SupportsNestedTypes
        {
            [Fx.Tag.SecurityNote(Critical = "Critical because it calls the CodeProvider.Supports(..) method that has a LinkDemand.",
                Safe = "Safe because it doesn't leak security sensitive information.")]
            [SecuritySafeCritical]
            get { return (CodeProvider == null) ? true : CodeProvider.Supports(GeneratorSupport.NestedTypes); }
        }
 
        string FileExtension
        {
            [Fx.Tag.SecurityNote(Critical = "Critical because it calls the CodeProvider.FileExtension property that has a LinkDemand.",
                Safe = "Safe because it doesn't leak security sensitive information.")]
            [SecuritySafeCritical]
            get { return (CodeProvider == null) ? String.Empty : CodeProvider.FileExtension; }
        }
 
        Dictionary<string, string> Namespaces
        {
            get { return namespaces; }
        }
 
        Dictionary<string, string> ClrNamespaces
        {
            get { return clrNamespaces; }
        }
 
 
        bool TryGetReferencedType(XmlQualifiedName stableName, DataContract dataContract, out Type type)
        {
            if (dataContract == null)
            {
                if (dataContractSet.TryGetReferencedCollectionType(stableName, dataContract, out type))
                    return true;
                if (dataContractSet.TryGetReferencedType(stableName, dataContract, out type))
                {
                    // enforce that collection types only be specified via ReferencedCollectionTypes 
                    if (CollectionDataContract.IsCollection(type))
                    {
                        type = null;
                        return false;
                    }
                    return true;
                }
                return false;
            }
            else if (dataContract is CollectionDataContract)
                return dataContractSet.TryGetReferencedCollectionType(stableName, dataContract, out type);
            else
            {
                XmlDataContract xmlDataContract = dataContract as XmlDataContract;
                if (xmlDataContract != null && xmlDataContract.IsAnonymous)
                {
                    stableName = SchemaImporter.ImportActualType(xmlDataContract.XsdType.Annotation, stableName, dataContract.StableName);
                }
                return dataContractSet.TryGetReferencedType(stableName, dataContract, out type);
            }
        }
 
        [Fx.Tag.SecurityNote(Critical = "Critical because it calls the System.CodeDom.Compiler.CodeGenerator.ValidateIdentifiers(..) method that has a LinkDemand for FullTrust.")]
        [SecurityCritical]
        internal void Export()
        {
            try
            {
                foreach (KeyValuePair<XmlQualifiedName, DataContract> pair in dataContractSet)
                {
                    DataContract dataContract = pair.Value;
                    if (dataContract.IsBuiltInDataContract)
                        continue;
 
                    ContractCodeDomInfo contractCodeDomInfo = GetContractCodeDomInfo(dataContract);
                    if (!contractCodeDomInfo.IsProcessed)
                    {
                        if (dataContract is ClassDataContract)
                        {
                            ClassDataContract classDataContract = (ClassDataContract)dataContract;
                            if (classDataContract.IsISerializable)
                                ExportISerializableDataContract(classDataContract, contractCodeDomInfo);
                            else
                                ExportClassDataContractHierarchy(classDataContract.StableName, classDataContract, contractCodeDomInfo, new Dictionary<XmlQualifiedName, object>());
                        }
                        else if (dataContract is CollectionDataContract)
                            ExportCollectionDataContract((CollectionDataContract)dataContract, contractCodeDomInfo);
                        else if (dataContract is EnumDataContract)
                            ExportEnumDataContract((EnumDataContract)dataContract, contractCodeDomInfo);
                        else if (dataContract is XmlDataContract)
                            ExportXmlDataContract((XmlDataContract)dataContract, contractCodeDomInfo);
                        else
                            throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.UnexpectedContractType, DataContract.GetClrTypeFullName(dataContract.GetType()), DataContract.GetClrTypeFullName(dataContract.UnderlyingType))));
                        contractCodeDomInfo.IsProcessed = true;
                    }
                }
                if (dataContractSet.DataContractSurrogate != null)
                {
                    CodeNamespace[] namespaces = new CodeNamespace[codeCompileUnit.Namespaces.Count];
                    codeCompileUnit.Namespaces.CopyTo(namespaces, 0);
                    foreach (CodeNamespace codeNamespace in namespaces)
                        InvokeProcessImportedType(codeNamespace.Types);
                }
            }
            finally
            {
                System.CodeDom.Compiler.CodeGenerator.ValidateIdentifiers(codeCompileUnit);
            }
        }
 
        void ExportClassDataContractHierarchy(XmlQualifiedName typeName, ClassDataContract classContract, ContractCodeDomInfo contractCodeDomInfo, Dictionary<XmlQualifiedName, object> contractNamesInHierarchy)
        {
            if (contractNamesInHierarchy.ContainsKey(classContract.StableName))
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.TypeCannotBeImported, typeName.Name, typeName.Namespace, SR.GetString(SR.CircularTypeReference, classContract.StableName.Name, classContract.StableName.Namespace))));
            contractNamesInHierarchy.Add(classContract.StableName, null);
 
            ClassDataContract baseContract = classContract.BaseContract;
            if (baseContract != null)
            {
                ContractCodeDomInfo baseContractCodeDomInfo = GetContractCodeDomInfo(baseContract);
                if (!baseContractCodeDomInfo.IsProcessed)
                {
                    ExportClassDataContractHierarchy(typeName, baseContract, baseContractCodeDomInfo, contractNamesInHierarchy);
                    baseContractCodeDomInfo.IsProcessed = true;
                }
            }
            ExportClassDataContract(classContract, contractCodeDomInfo);
        }
 
        void InvokeProcessImportedType(CollectionBase collection)
        {
            object[] objects = new object[collection.Count];
            ((ICollection)collection).CopyTo(objects, 0);
            foreach (object obj in objects)
            {
                CodeTypeDeclaration codeTypeDeclaration = obj as CodeTypeDeclaration;
                if (codeTypeDeclaration == null)
                    continue;
 
                CodeTypeDeclaration newCodeTypeDeclaration = DataContractSurrogateCaller.ProcessImportedType(
                                                                   dataContractSet.DataContractSurrogate,
                                                                   codeTypeDeclaration,
                                                                   codeCompileUnit);
                if (newCodeTypeDeclaration != codeTypeDeclaration)
                {
                    ((IList)collection).Remove(codeTypeDeclaration);
                    if (newCodeTypeDeclaration != null)
                        ((IList)collection).Add(newCodeTypeDeclaration);
                }
                if (newCodeTypeDeclaration != null)
                    InvokeProcessImportedType(newCodeTypeDeclaration.Members);
            }
        }
 
        internal CodeTypeReference GetCodeTypeReference(DataContract dataContract)
        {
            if (dataContract.IsBuiltInDataContract)
                return GetCodeTypeReference(dataContract.UnderlyingType);
 
            ContractCodeDomInfo contractCodeDomInfo = GetContractCodeDomInfo(dataContract);
            GenerateType(dataContract, contractCodeDomInfo);
            return contractCodeDomInfo.TypeReference;
        }
 
        CodeTypeReference GetCodeTypeReference(Type type)
        {
            AddReferencedAssembly(type.Assembly);
            return new CodeTypeReference(type);
        }
 
        internal CodeTypeReference GetElementTypeReference(DataContract dataContract, bool isElementTypeNullable)
        {
            CodeTypeReference elementTypeReference = GetCodeTypeReference(dataContract);
            if (dataContract.IsValueType && isElementTypeNullable)
                elementTypeReference = WrapNullable(elementTypeReference);
            return elementTypeReference;
        }
 
        XmlQualifiedName GenericListName
        {
            get { return DataContract.GetStableName(Globals.TypeOfListGeneric); }
        }
 
        CollectionDataContract GenericListContract
        {
            get { return dataContractSet.GetDataContract(Globals.TypeOfListGeneric) as CollectionDataContract; }
        }
 
        XmlQualifiedName GenericDictionaryName
        {
            get { return DataContract.GetStableName(Globals.TypeOfDictionaryGeneric); }
        }
 
        CollectionDataContract GenericDictionaryContract
        {
            get { return dataContractSet.GetDataContract(Globals.TypeOfDictionaryGeneric) as CollectionDataContract; }
        }
 
        ContractCodeDomInfo GetContractCodeDomInfo(DataContract dataContract)
        {
            ContractCodeDomInfo contractCodeDomInfo = dataContractSet.GetContractCodeDomInfo(dataContract);
            if (contractCodeDomInfo == null)
            {
                contractCodeDomInfo = new ContractCodeDomInfo();
                dataContractSet.SetContractCodeDomInfo(dataContract, contractCodeDomInfo);
            }
            return contractCodeDomInfo;
        }
 
        void GenerateType(DataContract dataContract, ContractCodeDomInfo contractCodeDomInfo)
        {
            if (!contractCodeDomInfo.IsProcessed)
            {
                CodeTypeReference referencedType = GetReferencedType(dataContract);
                if (referencedType != null)
                {
                    contractCodeDomInfo.TypeReference = referencedType;
                    contractCodeDomInfo.ReferencedTypeExists = true;
                }
                else
                {
                    CodeTypeDeclaration type = contractCodeDomInfo.TypeDeclaration;
                    if (type == null)
                    {
                        string clrNamespace = GetClrNamespace(dataContract, contractCodeDomInfo);
                        CodeNamespace ns = GetCodeNamespace(clrNamespace, dataContract.StableName.Namespace, contractCodeDomInfo);
                        type = GetNestedType(dataContract, contractCodeDomInfo);
                        if (type == null)
                        {
                            string typeName = XmlConvert.DecodeName(dataContract.StableName.Name);
                            typeName = GetClrIdentifier(typeName, Globals.DefaultTypeName);
                            if (NamespaceContainsType(ns, typeName) || GlobalTypeNameConflicts(clrNamespace, typeName))
                            {
                                for (int i = 1;; i++)
                                {
                                    string uniqueName = AppendToValidClrIdentifier(typeName, i.ToString(NumberFormatInfo.InvariantInfo));
                                    if (!NamespaceContainsType(ns, uniqueName) && !GlobalTypeNameConflicts(clrNamespace, uniqueName))
                                    {
                                        typeName = uniqueName;
                                        break;
                                    }
                                    if (i == Int32.MaxValue)
                                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.CannotComputeUniqueName, typeName)));
                                }
                            }
 
                            type = CreateTypeDeclaration(typeName, dataContract);
                            ns.Types.Add(type);
                            if (string.IsNullOrEmpty(clrNamespace))
                            {
                                AddGlobalTypeName(typeName);
                            }
                            contractCodeDomInfo.TypeReference = new CodeTypeReference((clrNamespace == null || clrNamespace.Length == 0) ? typeName : clrNamespace + "." + typeName);
 
                            if (GenerateInternalTypes)
                                type.TypeAttributes = TypeAttributes.NotPublic;
                            else
                                type.TypeAttributes = TypeAttributes.Public;
                        }
                        if (dataContractSet.DataContractSurrogate != null)
                            type.UserData.Add(surrogateDataKey, dataContractSet.GetSurrogateData(dataContract));
 
                        contractCodeDomInfo.TypeDeclaration = type;
                    }
                }
            }
        }
 
        CodeTypeDeclaration GetNestedType(DataContract dataContract, ContractCodeDomInfo contractCodeDomInfo)
        {
            if (!SupportsNestedTypes)
                return null;
            string originalName = dataContract.StableName.Name;
            int nestedTypeIndex = originalName.LastIndexOf('.');
            if (nestedTypeIndex <= 0)
                return null;
            string containingTypeName = originalName.Substring(0, nestedTypeIndex);
            DataContract containingDataContract = dataContractSet[new XmlQualifiedName(containingTypeName, dataContract.StableName.Namespace)];
            if (containingDataContract == null)
                return null;
            string nestedTypeName = XmlConvert.DecodeName(originalName.Substring(nestedTypeIndex + 1));
            nestedTypeName = GetClrIdentifier(nestedTypeName, Globals.DefaultTypeName);
 
            ContractCodeDomInfo containingContractCodeDomInfo = GetContractCodeDomInfo(containingDataContract);
            GenerateType(containingDataContract, containingContractCodeDomInfo);
            if (containingContractCodeDomInfo.ReferencedTypeExists)
                return null;
 
            CodeTypeDeclaration containingType = containingContractCodeDomInfo.TypeDeclaration;
            if (TypeContainsNestedType(containingType, nestedTypeName))
            {
                for (int i = 1;; i++)
                {
                    string uniqueName = AppendToValidClrIdentifier(nestedTypeName, i.ToString(NumberFormatInfo.InvariantInfo));
                    if (!TypeContainsNestedType(containingType, uniqueName))
                    {
                        nestedTypeName = uniqueName;
                        break;
                    }
                }
            }
 
            CodeTypeDeclaration type = CreateTypeDeclaration(nestedTypeName, dataContract);
            containingType.Members.Add(type);
            contractCodeDomInfo.TypeReference = new CodeTypeReference(containingContractCodeDomInfo.TypeReference.BaseType + "+" + nestedTypeName);
 
            if (GenerateInternalTypes)
                type.TypeAttributes = TypeAttributes.NestedAssembly;
            else
                type.TypeAttributes = TypeAttributes.NestedPublic;
            return type;
        }
 
        static CodeTypeDeclaration CreateTypeDeclaration(string typeName, DataContract dataContract)
        {
            CodeTypeDeclaration typeDecl = new CodeTypeDeclaration(typeName);
            CodeAttributeDeclaration debuggerStepThroughAttribute = new CodeAttributeDeclaration(typeof(System.Diagnostics.DebuggerStepThroughAttribute).FullName);
            CodeAttributeDeclaration generatedCodeAttribute = new CodeAttributeDeclaration(typeof(GeneratedCodeAttribute).FullName);
 
            AssemblyName assemblyName = Assembly.GetExecutingAssembly().GetName();
            generatedCodeAttribute.Arguments.Add(new CodeAttributeArgument(new CodePrimitiveExpression(assemblyName.Name)));
            generatedCodeAttribute.Arguments.Add(new CodeAttributeArgument(new CodePrimitiveExpression(assemblyName.Version.ToString())));
 
            // System.Diagnostics.DebuggerStepThroughAttribute not allowed on enums
            // ensure that the attribute is only generated on types that are not enums
            EnumDataContract enumDataContract = dataContract as EnumDataContract;
            if (enumDataContract == null)
            {
                typeDecl.CustomAttributes.Add(debuggerStepThroughAttribute);
            }
            typeDecl.CustomAttributes.Add(generatedCodeAttribute);
            return typeDecl;
        }
 
        [Fx.Tag.SecurityNote(Critical = "Sets critical properties on internal XmlDataContract.",
            Safe = "Called during schema import/code generation.")]
        [SecuritySafeCritical]
        CodeTypeReference GetReferencedType(DataContract dataContract)
        {
            Type type = null;
            CodeTypeReference typeReference = GetSurrogatedTypeReference(dataContract);
            if (typeReference != null)
                return typeReference;
 
            if (TryGetReferencedType(dataContract.StableName, dataContract, out type)
                && !type.IsGenericTypeDefinition && !type.ContainsGenericParameters)
            {
                if (dataContract is XmlDataContract)
                {
                    if (Globals.TypeOfIXmlSerializable.IsAssignableFrom(type))
                    {
                        XmlDataContract xmlContract = (XmlDataContract)dataContract;
                        if (xmlContract.IsTypeDefinedOnImport)
                        {
                            if (!xmlContract.Equals(dataContractSet.GetDataContract(type)))
                                throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ReferencedTypeDoesNotMatch, type.AssemblyQualifiedName, dataContract.StableName.Name, dataContract.StableName.Namespace)));
                        }
                        else
                        {
                            xmlContract.IsValueType = type.IsValueType;
                            xmlContract.IsTypeDefinedOnImport = true;
                        }
                        return GetCodeTypeReference(type);
                    }
                    throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.TypeMustBeIXmlSerializable, DataContract.GetClrTypeFullName(type), DataContract.GetClrTypeFullName(Globals.TypeOfIXmlSerializable), dataContract.StableName.Name, dataContract.StableName.Namespace)));
                }
                DataContract referencedContract = dataContractSet.GetDataContract(type);
                if (referencedContract.Equals(dataContract))
                {
                    typeReference = GetCodeTypeReference(type);
                    typeReference.UserData.Add(codeUserDataActualTypeKey, type);
                    return typeReference;
                }
                throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ReferencedTypeDoesNotMatch, type.AssemblyQualifiedName, dataContract.StableName.Name, dataContract.StableName.Namespace)));
            }
            else if (dataContract.GenericInfo != null)
            {
                DataContract referencedContract;
                XmlQualifiedName genericStableName = dataContract.GenericInfo.GetExpandedStableName();
                if (genericStableName != dataContract.StableName)
                    throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.GenericTypeNameMismatch, dataContract.StableName.Name, dataContract.StableName.Namespace, genericStableName.Name, genericStableName.Namespace)));
 
                typeReference = GetReferencedGenericType(dataContract.GenericInfo, out referencedContract);
                if (referencedContract != null && !referencedContract.Equals(dataContract))
                {
                    type = (Type)typeReference.UserData[codeUserDataActualTypeKey];
                    throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ReferencedTypeDoesNotMatch,
                        type.AssemblyQualifiedName,
                        referencedContract.StableName.Name,
                        referencedContract.StableName.Namespace)));
                }
                return typeReference;
            }
 
            return GetReferencedCollectionType(dataContract as CollectionDataContract);
        }
 
        CodeTypeReference GetReferencedCollectionType(CollectionDataContract collectionContract)
        {
            if (collectionContract == null)
                return null;
 
            if (HasDefaultCollectionNames(collectionContract))
            {
                CodeTypeReference typeReference;
                if (!TryGetReferencedDictionaryType(collectionContract, out typeReference))
                {
                    DataContract itemContract = collectionContract.ItemContract;
                    if (collectionContract.IsDictionary)
                    {
                        GenerateKeyValueType(itemContract as ClassDataContract);
                    }
                    bool isItemTypeNullable = collectionContract.IsItemTypeNullable;
                    if (!TryGetReferencedListType(itemContract, isItemTypeNullable, out typeReference))
                        typeReference = new CodeTypeReference(GetElementTypeReference(itemContract, isItemTypeNullable), 1);
                }
                return typeReference;
            }
            return null;
        }
 
        bool HasDefaultCollectionNames(CollectionDataContract collectionContract)
        {
            DataContract itemContract = collectionContract.ItemContract;
            if (collectionContract.ItemName != itemContract.StableName.Name)
                return false;
 
            if (collectionContract.IsDictionary &&
                (collectionContract.KeyName != Globals.KeyLocalName || collectionContract.ValueName != Globals.ValueLocalName))
                return false;
 
            XmlQualifiedName expectedType = itemContract.GetArrayTypeName(collectionContract.IsItemTypeNullable);
            return (collectionContract.StableName.Name == expectedType.Name && collectionContract.StableName.Namespace == expectedType.Namespace);
        }
 
        bool TryGetReferencedDictionaryType(CollectionDataContract collectionContract, out CodeTypeReference typeReference)
        {
            // Check if it is a dictionary and use referenced dictionary type if present
            if (collectionContract.IsDictionary
                && SupportsGenericTypeReference)
            {
                Type type;
                if (!TryGetReferencedType(GenericDictionaryName, GenericDictionaryContract, out type))
                    type = Globals.TypeOfDictionaryGeneric;
                ClassDataContract itemContract = collectionContract.ItemContract as ClassDataContract;
                DataMember keyMember = itemContract.Members[0];
                DataMember valueMember = itemContract.Members[1];
                CodeTypeReference keyTypeReference = GetElementTypeReference(keyMember.MemberTypeContract, keyMember.IsNullable);
                CodeTypeReference valueTypeReference = GetElementTypeReference(valueMember.MemberTypeContract, valueMember.IsNullable);
                if (keyTypeReference != null && valueTypeReference != null)
                {
                    typeReference = GetCodeTypeReference(type);
                    typeReference.TypeArguments.Add(keyTypeReference);
                    typeReference.TypeArguments.Add(valueTypeReference);
                    return true;
                }
            }
            typeReference = null;
            return false;
        }
 
        bool TryGetReferencedListType(DataContract itemContract, bool isItemTypeNullable, out CodeTypeReference typeReference)
        {
            Type type;
            if (SupportsGenericTypeReference && TryGetReferencedType(GenericListName, GenericListContract, out type))
            {
                typeReference = GetCodeTypeReference(type);
                typeReference.TypeArguments.Add(GetElementTypeReference(itemContract, isItemTypeNullable));
                return true;
            }
            typeReference = null;
            return false;
        }
 
        CodeTypeReference GetSurrogatedTypeReference(DataContract dataContract)
        {
            IDataContractSurrogate dataContractSurrogate = this.dataContractSet.DataContractSurrogate;
            if (dataContractSurrogate != null)
            {
                Type type = DataContractSurrogateCaller.GetReferencedTypeOnImport(
                        dataContractSurrogate,
                        dataContract.StableName.Name,
                        dataContract.StableName.Namespace,
                        dataContractSet.GetSurrogateData(dataContract));
                if (type != null)
                {
                    CodeTypeReference typeReference = GetCodeTypeReference(type);
                    typeReference.UserData.Add(codeUserDataActualTypeKey, type);
                    return typeReference;
                }
            }
            return null;
        }
 
        CodeTypeReference GetReferencedGenericType(GenericInfo genInfo, out DataContract dataContract)
        {
            dataContract = null;
 
            if (!SupportsGenericTypeReference)
                return null;
 
            Type type;
            if (!TryGetReferencedType(genInfo.StableName, null, out type))
            {
                if (genInfo.Parameters != null)
                    return null;
                dataContract = dataContractSet[genInfo.StableName];
                if (dataContract == null)
                    return null;
                if (dataContract.GenericInfo != null)
                    return null;
                return GetCodeTypeReference(dataContract);
            }
 
            bool enableStructureCheck = (type != Globals.TypeOfNullable);
            CodeTypeReference typeReference = GetCodeTypeReference(type);
            typeReference.UserData.Add(codeUserDataActualTypeKey, type);
            if (genInfo.Parameters != null)
            {
                DataContract[] paramContracts = new DataContract[genInfo.Parameters.Count];
                for (int i = 0; i < genInfo.Parameters.Count; i++)
                {
                    GenericInfo paramInfo = genInfo.Parameters[i];
                    XmlQualifiedName stableName = paramInfo.GetExpandedStableName();
                    DataContract paramContract = dataContractSet[stableName];
 
                    CodeTypeReference paramTypeReference;
                    bool isParamValueType;
                    if (paramContract != null)
                    {
                        paramTypeReference = GetCodeTypeReference(paramContract);
                        isParamValueType = paramContract.IsValueType;
                    }
                    else
                    {
                        paramTypeReference = GetReferencedGenericType(paramInfo, out paramContract);
                        isParamValueType = (paramTypeReference != null && paramTypeReference.ArrayRank == 0); // only value type information we can get from CodeTypeReference
                    }
                    paramContracts[i] = paramContract;
                    if (paramContract == null)
                        enableStructureCheck = false;
                    if (paramTypeReference == null)
                        return null;
                    if (type == Globals.TypeOfNullable && !isParamValueType)
                        return paramTypeReference;
                    else
                        typeReference.TypeArguments.Add(paramTypeReference);
                }
                if (enableStructureCheck)
                    dataContract = DataContract.GetDataContract(type).BindGenericParameters(paramContracts, new Dictionary<DataContract, DataContract>());
            }
            return typeReference;
        }
 
        bool NamespaceContainsType(CodeNamespace ns, string typeName)
        {
            foreach (CodeTypeDeclaration type in ns.Types)
            {
                if (String.Compare(typeName, type.Name, StringComparison.OrdinalIgnoreCase) == 0)
                    return true;
            }
            return false;
        }
 
        bool GlobalTypeNameConflicts(string clrNamespace, string typeName)
        {
            return (string.IsNullOrEmpty(clrNamespace) && this.clrNamespaces.ContainsKey(typeName));
        }
 
        void AddGlobalTypeName(string typeName)
        {
            if (!this.clrNamespaces.ContainsKey(typeName))
            {
                this.clrNamespaces.Add(typeName, null);
            }
        }
 
        bool TypeContainsNestedType(CodeTypeDeclaration containingType, string typeName)
        {
            foreach (CodeTypeMember member in containingType.Members)
            {
                if (member is CodeTypeDeclaration)
                {
                    if (String.Compare(typeName, ((CodeTypeDeclaration)member).Name, StringComparison.OrdinalIgnoreCase) == 0)
                        return true;
                }
            }
            return false;
        }
 
        string GetNameForAttribute(string name)
        {
            string decodedName = XmlConvert.DecodeName(name);
            if (string.CompareOrdinal(name, decodedName) == 0)
                return name;
            string reencodedName = DataContract.EncodeLocalName(decodedName);
            return (string.CompareOrdinal(name, reencodedName) == 0) ? decodedName : name;
        }
 
        void AddSerializableAttribute(bool generateSerializable, CodeTypeDeclaration type, ContractCodeDomInfo contractCodeDomInfo)
        {
            if (generateSerializable)
            {
                type.CustomAttributes.Add(SerializableAttribute);
                AddImportStatement(Globals.TypeOfSerializableAttribute.Namespace, contractCodeDomInfo.CodeNamespace);
            }
        }
 
        void ExportClassDataContract(ClassDataContract classDataContract, ContractCodeDomInfo contractCodeDomInfo)
        {
            GenerateType(classDataContract, contractCodeDomInfo);
            if (contractCodeDomInfo.ReferencedTypeExists)
                return;
 
            CodeTypeDeclaration type = contractCodeDomInfo.TypeDeclaration;
            if (SupportsPartialTypes)
                type.IsPartial = true;
            if (classDataContract.IsValueType && SupportsDeclareValueTypes)
                type.IsStruct = true;
            else
                type.IsClass = true;
 
            string dataContractName = GetNameForAttribute(classDataContract.StableName.Name);
            CodeAttributeDeclaration dataContractAttribute = new CodeAttributeDeclaration(DataContract.GetClrTypeFullName(Globals.TypeOfDataContractAttribute));
            dataContractAttribute.Arguments.Add(new CodeAttributeArgument(Globals.NameProperty, new CodePrimitiveExpression(dataContractName)));
            dataContractAttribute.Arguments.Add(new CodeAttributeArgument(Globals.NamespaceProperty, new CodePrimitiveExpression(classDataContract.StableName.Namespace)));
            if (classDataContract.IsReference != Globals.DefaultIsReference)
                dataContractAttribute.Arguments.Add(new CodeAttributeArgument(Globals.IsReferenceProperty, new CodePrimitiveExpression(classDataContract.IsReference)));
            type.CustomAttributes.Add(dataContractAttribute);
            AddImportStatement(Globals.TypeOfDataContractAttribute.Namespace, contractCodeDomInfo.CodeNamespace);
 
            AddSerializableAttribute(GenerateSerializableTypes, type, contractCodeDomInfo);
 
            AddKnownTypes(classDataContract, contractCodeDomInfo);
 
            bool raisePropertyChanged = EnableDataBinding && SupportsDeclareEvents;
            if (classDataContract.BaseContract == null)
            {
                if (!type.IsStruct)
                    type.BaseTypes.Add(Globals.TypeOfObject);
                AddExtensionData(contractCodeDomInfo);
                AddPropertyChangedNotifier(contractCodeDomInfo, type.IsStruct);
            }
            else
            {
                ContractCodeDomInfo baseContractCodeDomInfo = GetContractCodeDomInfo(classDataContract.BaseContract);
                Fx.Assert(baseContractCodeDomInfo.IsProcessed, "Cannot generate code for type if code for base type has not been generated");
                type.BaseTypes.Add(baseContractCodeDomInfo.TypeReference);
                AddBaseMemberNames(baseContractCodeDomInfo, contractCodeDomInfo);
                if (baseContractCodeDomInfo.ReferencedTypeExists)
                {
                    Type actualType = (Type)baseContractCodeDomInfo.TypeReference.UserData[codeUserDataActualTypeKey];
                    ThrowIfReferencedBaseTypeSealed(actualType, classDataContract);
                    if (!Globals.TypeOfIExtensibleDataObject.IsAssignableFrom(actualType))
                        AddExtensionData(contractCodeDomInfo);
                    if (!Globals.TypeOfIPropertyChange.IsAssignableFrom(actualType))
                    {
                        AddPropertyChangedNotifier(contractCodeDomInfo, type.IsStruct);
                    }
                    else
                    {
                        raisePropertyChanged = false;
                    }
                }
            }
 
            if (classDataContract.Members != null)
            {
                for (int i = 0; i < classDataContract.Members.Count; i++)
                {
                    DataMember dataMember = classDataContract.Members[i];
 
                    CodeTypeReference memberType = GetElementTypeReference(dataMember.MemberTypeContract,
                        (dataMember.IsNullable && dataMember.MemberTypeContract.IsValueType));
 
                    string dataMemberName = GetNameForAttribute(dataMember.Name);
                    string propertyName = GetMemberName(dataMemberName, contractCodeDomInfo);
                    string fieldName = GetMemberName(AppendToValidClrIdentifier(propertyName, Globals.DefaultFieldSuffix), contractCodeDomInfo);
 
                    CodeMemberField field = new CodeMemberField();
                    field.Type = memberType;
                    field.Name = fieldName;
                    field.Attributes = MemberAttributes.Private;
 
                    CodeMemberProperty property = CreateProperty(memberType, propertyName, fieldName, dataMember.MemberTypeContract.IsValueType && SupportsDeclareValueTypes, raisePropertyChanged);
                    if (dataContractSet.DataContractSurrogate != null)
                        property.UserData.Add(surrogateDataKey, dataContractSet.GetSurrogateData(dataMember));
 
                    CodeAttributeDeclaration dataMemberAttribute = new CodeAttributeDeclaration(DataContract.GetClrTypeFullName(Globals.TypeOfDataMemberAttribute));
                    if (dataMemberName != property.Name)
                        dataMemberAttribute.Arguments.Add(new CodeAttributeArgument(Globals.NameProperty, new CodePrimitiveExpression(dataMemberName)));
                    if (dataMember.IsRequired != Globals.DefaultIsRequired)
                        dataMemberAttribute.Arguments.Add(new CodeAttributeArgument(Globals.IsRequiredProperty, new CodePrimitiveExpression(dataMember.IsRequired)));
                    if (dataMember.EmitDefaultValue != Globals.DefaultEmitDefaultValue)
                        dataMemberAttribute.Arguments.Add(new CodeAttributeArgument(Globals.EmitDefaultValueProperty, new CodePrimitiveExpression(dataMember.EmitDefaultValue)));
                    if (dataMember.Order != Globals.DefaultOrder)
                        dataMemberAttribute.Arguments.Add(new CodeAttributeArgument(Globals.OrderProperty, new CodePrimitiveExpression(dataMember.Order)));
                    property.CustomAttributes.Add(dataMemberAttribute);
 
                    if (GenerateSerializableTypes && !dataMember.IsRequired)
                    {
                        CodeAttributeDeclaration optionalFieldAttribute = new CodeAttributeDeclaration(DataContract.GetClrTypeFullName(Globals.TypeOfOptionalFieldAttribute));
                        field.CustomAttributes.Add(optionalFieldAttribute);
                    }
 
                    type.Members.Add(field);
                    type.Members.Add(property);
                }
            }
        }
 
        bool CanDeclareAssemblyAttribute(ContractCodeDomInfo contractCodeDomInfo)
        {
            return SupportsAssemblyAttributes && !contractCodeDomInfo.UsesWildcardNamespace;
        }
 
        bool NeedsExplicitNamespace(string dataContractNamespace, string clrNamespace)
        {
            return (DataContract.GetDefaultStableNamespace(clrNamespace) != dataContractNamespace);
        }
 
        internal ICollection<CodeTypeReference> GetKnownTypeReferences(DataContract dataContract)
        {
            DataContractDictionary knownTypeDictionary = GetKnownTypeContracts(dataContract);
            if (knownTypeDictionary == null)
                return null;
 
            ICollection<DataContract> knownTypeContracts = knownTypeDictionary.Values;
            if (knownTypeContracts == null || knownTypeContracts.Count == 0)
                return null;
 
            List<CodeTypeReference> knownTypeReferences = new List<CodeTypeReference>();
            foreach (DataContract knownTypeContract in knownTypeContracts)
            {
                knownTypeReferences.Add(GetCodeTypeReference(knownTypeContract));
            }
            return knownTypeReferences;
        }
 
        DataContractDictionary GetKnownTypeContracts(DataContract dataContract)
        {
            if (dataContractSet.KnownTypesForObject != null && SchemaImporter.IsObjectContract(dataContract))
            {
                return dataContractSet.KnownTypesForObject;
            }
            else if (dataContract is ClassDataContract)
            {
                ContractCodeDomInfo contractCodeDomInfo = GetContractCodeDomInfo(dataContract);
                if (!contractCodeDomInfo.IsProcessed)
                    GenerateType(dataContract, contractCodeDomInfo);
                if (contractCodeDomInfo.ReferencedTypeExists)
                    return GetKnownTypeContracts((ClassDataContract)dataContract, new Dictionary<DataContract, object>());
            }
            return null;
        }
 
        DataContractDictionary GetKnownTypeContracts(ClassDataContract dataContract, Dictionary<DataContract, object> handledContracts)
        {
            if (handledContracts.ContainsKey(dataContract))
                return dataContract.KnownDataContracts;
 
            handledContracts.Add(dataContract, null);
            if (dataContract.Members != null)
            {
                bool objectMemberHandled = false;
                foreach (DataMember dataMember in dataContract.Members)
                {
                    DataContract memberContract = dataMember.MemberTypeContract;
                    if (!objectMemberHandled && dataContractSet.KnownTypesForObject != null && SchemaImporter.IsObjectContract(memberContract))
                    {
                        AddKnownTypeContracts(dataContract, dataContractSet.KnownTypesForObject);
                        objectMemberHandled = true;
                    }
                    else if (memberContract is ClassDataContract)
                    {
                        ContractCodeDomInfo memberCodeDomInfo = GetContractCodeDomInfo(memberContract);
                        if (!memberCodeDomInfo.IsProcessed)
                            GenerateType(memberContract, memberCodeDomInfo);
                        if (memberCodeDomInfo.ReferencedTypeExists)
                        {
                            AddKnownTypeContracts(dataContract, GetKnownTypeContracts((ClassDataContract)memberContract, handledContracts));
                        }
                    }
                }
            }
 
            return dataContract.KnownDataContracts;
        }
 
        [Fx.Tag.SecurityNote(Critical = "Sets critical properties on internal DataContract.",
            Safe = "Called during schema import/code generation.")]
        [SecuritySafeCritical]
        void AddKnownTypeContracts(ClassDataContract dataContract, DataContractDictionary knownContracts)
        {
            if (knownContracts == null || knownContracts.Count == 0)
                return;
 
            if (dataContract.KnownDataContracts == null)
                dataContract.KnownDataContracts = new DataContractDictionary();
 
            foreach (KeyValuePair<XmlQualifiedName, DataContract> pair in knownContracts)
            {
                if (dataContract.StableName != pair.Key && !dataContract.KnownDataContracts.ContainsKey(pair.Key) && !pair.Value.IsBuiltInDataContract)
                    dataContract.KnownDataContracts.Add(pair.Key, pair.Value);
            }
        }
 
        void AddKnownTypes(ClassDataContract dataContract, ContractCodeDomInfo contractCodeDomInfo)
        {
            DataContractDictionary knownContractDictionary = GetKnownTypeContracts(dataContract, new Dictionary<DataContract, object>());
            if (knownContractDictionary == null || knownContractDictionary.Count == 0)
                return;
 
            ICollection<DataContract> knownTypeContracts = knownContractDictionary.Values;
            foreach (DataContract knownTypeContract in knownTypeContracts)
            {
                CodeAttributeDeclaration knownTypeAttribute = new CodeAttributeDeclaration(DataContract.GetClrTypeFullName(Globals.TypeOfKnownTypeAttribute));
                knownTypeAttribute.Arguments.Add(new CodeAttributeArgument(new CodeTypeOfExpression(GetCodeTypeReference(knownTypeContract))));
                contractCodeDomInfo.TypeDeclaration.CustomAttributes.Add(knownTypeAttribute);
            }
            AddImportStatement(Globals.TypeOfKnownTypeAttribute.Namespace, contractCodeDomInfo.CodeNamespace);
        }
 
        CodeTypeReference WrapNullable(CodeTypeReference memberType)
        {
            if (!SupportsGenericTypeReference)
                return memberType;
 
            CodeTypeReference nullableOfMemberType = GetCodeTypeReference(Globals.TypeOfNullable);
            nullableOfMemberType.TypeArguments.Add(memberType);
            return nullableOfMemberType;
        }
 
        void AddExtensionData(ContractCodeDomInfo contractCodeDomInfo)
        {
            if (contractCodeDomInfo != null && contractCodeDomInfo.TypeDeclaration != null)
            {
                CodeTypeDeclaration type = contractCodeDomInfo.TypeDeclaration;
                type.BaseTypes.Add(DataContract.GetClrTypeFullName(Globals.TypeOfIExtensibleDataObject));
                CodeMemberField extensionDataObjectField = ExtensionDataObjectField;
                if (GenerateSerializableTypes)
                {
                    CodeAttributeDeclaration nonSerializedAttribute = new CodeAttributeDeclaration(DataContract.GetClrTypeFullName(Globals.TypeOfNonSerializedAttribute));
                    extensionDataObjectField.CustomAttributes.Add(nonSerializedAttribute);
                }
                type.Members.Add(extensionDataObjectField);
                contractCodeDomInfo.GetMemberNames().Add(extensionDataObjectField.Name, null);
                CodeMemberProperty extensionDataObjectProperty = ExtensionDataObjectProperty;
                type.Members.Add(extensionDataObjectProperty);
                contractCodeDomInfo.GetMemberNames().Add(extensionDataObjectProperty.Name, null);
            }
        }
 
        void AddPropertyChangedNotifier(ContractCodeDomInfo contractCodeDomInfo, bool isValueType)
        {
            if (EnableDataBinding && SupportsDeclareEvents && contractCodeDomInfo != null && contractCodeDomInfo.TypeDeclaration != null)
            {
                CodeTypeDeclaration codeTypeDeclaration = contractCodeDomInfo.TypeDeclaration;
                codeTypeDeclaration.BaseTypes.Add(CodeTypeIPropertyChange);
                CodeMemberEvent memberEvent = PropertyChangedEvent;
                codeTypeDeclaration.Members.Add(memberEvent);
                CodeMemberMethod raisePropertyChangedEventMethod = RaisePropertyChangedEventMethod;
                if (!isValueType)
                    raisePropertyChangedEventMethod.Attributes |= MemberAttributes.Family;
                codeTypeDeclaration.Members.Add(raisePropertyChangedEventMethod);
                contractCodeDomInfo.GetMemberNames().Add(memberEvent.Name, null);
                contractCodeDomInfo.GetMemberNames().Add(raisePropertyChangedEventMethod.Name, null);
            }
        }
 
        void ThrowIfReferencedBaseTypeSealed(Type baseType, DataContract dataContract)
        {
            if (baseType.IsSealed)
                throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.CannotDeriveFromSealedReferenceType, dataContract.StableName.Name, dataContract.StableName.Namespace, DataContract.GetClrTypeFullName(baseType))));
        }
 
        void ExportEnumDataContract(EnumDataContract enumDataContract, ContractCodeDomInfo contractCodeDomInfo)
        {
            GenerateType(enumDataContract, contractCodeDomInfo);
            if (contractCodeDomInfo.ReferencedTypeExists)
                return;
 
            CodeTypeDeclaration type = contractCodeDomInfo.TypeDeclaration;
            type.IsEnum = true;
            type.BaseTypes.Add(EnumDataContract.GetBaseType(enumDataContract.BaseContractName));
            if (enumDataContract.IsFlags)
            {
                type.CustomAttributes.Add(new CodeAttributeDeclaration(DataContract.GetClrTypeFullName(Globals.TypeOfFlagsAttribute)));
                AddImportStatement(Globals.TypeOfFlagsAttribute.Namespace, contractCodeDomInfo.CodeNamespace);
            }
 
            string dataContractName = GetNameForAttribute(enumDataContract.StableName.Name);
            CodeAttributeDeclaration dataContractAttribute = new CodeAttributeDeclaration(DataContract.GetClrTypeFullName(Globals.TypeOfDataContractAttribute));
            dataContractAttribute.Arguments.Add(new CodeAttributeArgument(Globals.NameProperty, new CodePrimitiveExpression(dataContractName)));
            dataContractAttribute.Arguments.Add(new CodeAttributeArgument(Globals.NamespaceProperty, new CodePrimitiveExpression(enumDataContract.StableName.Namespace)));
            type.CustomAttributes.Add(dataContractAttribute);
            AddImportStatement(Globals.TypeOfDataContractAttribute.Namespace, contractCodeDomInfo.CodeNamespace);
 
            if (enumDataContract.Members != null)
            {
                for (int i = 0; i < enumDataContract.Members.Count; i++)
                {
                    string stringValue = enumDataContract.Members[i].Name;
                    long longValue = enumDataContract.Values[i];
 
                    CodeMemberField enumMember = new CodeMemberField();
                    if (enumDataContract.IsULong)
                        enumMember.InitExpression = new CodeSnippetExpression(enumDataContract.GetStringFromEnumValue(longValue));
                    else
                        enumMember.InitExpression = new CodePrimitiveExpression(longValue);
                    enumMember.Name = GetMemberName(stringValue, contractCodeDomInfo);
                    CodeAttributeDeclaration enumMemberAttribute = new CodeAttributeDeclaration(DataContract.GetClrTypeFullName(Globals.TypeOfEnumMemberAttribute));
                    if (enumMember.Name != stringValue)
                        enumMemberAttribute.Arguments.Add(new CodeAttributeArgument(Globals.ValueProperty, new CodePrimitiveExpression(stringValue)));
                    enumMember.CustomAttributes.Add(enumMemberAttribute);
                    type.Members.Add(enumMember);
                }
            }
        }
 
        void ExportISerializableDataContract(ClassDataContract dataContract, ContractCodeDomInfo contractCodeDomInfo)
        {
            GenerateType(dataContract, contractCodeDomInfo);
            if (contractCodeDomInfo.ReferencedTypeExists)
                return;
 
            if (DataContract.GetDefaultStableNamespace(contractCodeDomInfo.ClrNamespace) != dataContract.StableName.Namespace)
                throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.InvalidClrNamespaceGeneratedForISerializable, dataContract.StableName.Name, dataContract.StableName.Namespace, DataContract.GetDataContractNamespaceFromUri(dataContract.StableName.Namespace), contractCodeDomInfo.ClrNamespace)));
            string dataContractName = GetNameForAttribute(dataContract.StableName.Name);
            int nestedTypeIndex = dataContractName.LastIndexOf('.');
            string expectedName = (nestedTypeIndex <= 0 || nestedTypeIndex == dataContractName.Length - 1) ? dataContractName : dataContractName.Substring(nestedTypeIndex + 1);
            if (contractCodeDomInfo.TypeDeclaration.Name != expectedName)
                throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.InvalidClrNameGeneratedForISerializable, dataContract.StableName.Name, dataContract.StableName.Namespace, contractCodeDomInfo.TypeDeclaration.Name)));
 
            CodeTypeDeclaration type = contractCodeDomInfo.TypeDeclaration;
            if (SupportsPartialTypes)
                type.IsPartial = true;
            if (dataContract.IsValueType && SupportsDeclareValueTypes)
                type.IsStruct = true;
            else
                type.IsClass = true;
 
            AddSerializableAttribute(true /*generateSerializable*/, type, contractCodeDomInfo);
 
            AddKnownTypes(dataContract, contractCodeDomInfo);
 
            if (dataContract.BaseContract == null)
            {
                if (!type.IsStruct)
                    type.BaseTypes.Add(Globals.TypeOfObject);
                type.BaseTypes.Add(DataContract.GetClrTypeFullName(Globals.TypeOfISerializable));
                type.Members.Add(ISerializableBaseConstructor);
                type.Members.Add(SerializationInfoField);
                type.Members.Add(SerializationInfoProperty);
                type.Members.Add(GetObjectDataMethod);
                AddPropertyChangedNotifier(contractCodeDomInfo, type.IsStruct);
            }
            else
            {
                ContractCodeDomInfo baseContractCodeDomInfo = GetContractCodeDomInfo(dataContract.BaseContract);
                GenerateType(dataContract.BaseContract, baseContractCodeDomInfo);
                type.BaseTypes.Add(baseContractCodeDomInfo.TypeReference);
                if (baseContractCodeDomInfo.ReferencedTypeExists)
                {
                    Type actualType = (Type)baseContractCodeDomInfo.TypeReference.UserData[codeUserDataActualTypeKey];
                    ThrowIfReferencedBaseTypeSealed(actualType, dataContract);
                }
                type.Members.Add(ISerializableDerivedConstructor);
            }
        }
 
        void GenerateKeyValueType(ClassDataContract keyValueContract)
        {
            // Add code for KeyValue item type in the case where its usage is limited to dictionary 
            // and dictionary is not found in referenced types
            if (keyValueContract != null && dataContractSet[keyValueContract.StableName] == null)
            {
                ContractCodeDomInfo contractCodeDomInfo = dataContractSet.GetContractCodeDomInfo(keyValueContract);
                if (contractCodeDomInfo == null)
                {
                    contractCodeDomInfo = new ContractCodeDomInfo();
                    dataContractSet.SetContractCodeDomInfo(keyValueContract, contractCodeDomInfo);
                    ExportClassDataContract(keyValueContract, contractCodeDomInfo);
                    contractCodeDomInfo.IsProcessed = true;
                }
            }
        }
 
        void ExportCollectionDataContract(CollectionDataContract collectionContract, ContractCodeDomInfo contractCodeDomInfo)
        {
            GenerateType(collectionContract, contractCodeDomInfo);
            if (contractCodeDomInfo.ReferencedTypeExists)
                return;
 
            string dataContractName = GetNameForAttribute(collectionContract.StableName.Name);
 
            // If type name is not expected, generate collection type that derives from referenced list type and uses [CollectionDataContract] 
            if (!SupportsGenericTypeReference)
                throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
                    SR.GetString(SR.CannotUseGenericTypeAsBase, dataContractName,
                    collectionContract.StableName.Namespace)));
 
            DataContract itemContract = collectionContract.ItemContract;
            bool isItemTypeNullable = collectionContract.IsItemTypeNullable;
 
            CodeTypeReference baseTypeReference;
            bool foundDictionaryBase = TryGetReferencedDictionaryType(collectionContract, out baseTypeReference);
            if (!foundDictionaryBase)
            {
                if (collectionContract.IsDictionary)
                {
                    GenerateKeyValueType(collectionContract.ItemContract as ClassDataContract);
                }
                if (!TryGetReferencedListType(itemContract, isItemTypeNullable, out baseTypeReference))
                {
                    if (SupportsGenericTypeReference)
                    {
                        baseTypeReference = GetCodeTypeReference(Globals.TypeOfListGeneric);
                        baseTypeReference.TypeArguments.Add(GetElementTypeReference(itemContract, isItemTypeNullable));
                    }
                    else
                    {
                        string expectedTypeName = Globals.ArrayPrefix + itemContract.StableName.Name;
                        string expectedTypeNs = DataContract.GetCollectionNamespace(itemContract.StableName.Namespace);
                        throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ReferencedBaseTypeDoesNotExist,
                            dataContractName, collectionContract.StableName.Namespace,
                            expectedTypeName, expectedTypeNs, DataContract.GetClrTypeFullName(Globals.TypeOfIListGeneric), DataContract.GetClrTypeFullName(Globals.TypeOfICollectionGeneric))));
                    }
                }
            }
 
            CodeTypeDeclaration generatedType = contractCodeDomInfo.TypeDeclaration;
            generatedType.BaseTypes.Add(baseTypeReference);
            CodeAttributeDeclaration collectionContractAttribute = new CodeAttributeDeclaration(DataContract.GetClrTypeFullName(Globals.TypeOfCollectionDataContractAttribute));
            collectionContractAttribute.Arguments.Add(new CodeAttributeArgument(Globals.NameProperty, new CodePrimitiveExpression(dataContractName)));
            collectionContractAttribute.Arguments.Add(new CodeAttributeArgument(Globals.NamespaceProperty, new CodePrimitiveExpression(collectionContract.StableName.Namespace)));
            if (collectionContract.IsReference != Globals.DefaultIsReference)
                collectionContractAttribute.Arguments.Add(new CodeAttributeArgument(Globals.IsReferenceProperty, new CodePrimitiveExpression(collectionContract.IsReference)));
            collectionContractAttribute.Arguments.Add(new CodeAttributeArgument(Globals.ItemNameProperty, new CodePrimitiveExpression(GetNameForAttribute(collectionContract.ItemName))));
            if (foundDictionaryBase)
            {
                collectionContractAttribute.Arguments.Add(new CodeAttributeArgument(Globals.KeyNameProperty, new CodePrimitiveExpression(GetNameForAttribute(collectionContract.KeyName))));
                collectionContractAttribute.Arguments.Add(new CodeAttributeArgument(Globals.ValueNameProperty, new CodePrimitiveExpression(GetNameForAttribute(collectionContract.ValueName))));
            }
            generatedType.CustomAttributes.Add(collectionContractAttribute);
            AddImportStatement(Globals.TypeOfCollectionDataContractAttribute.Namespace, contractCodeDomInfo.CodeNamespace);
            AddSerializableAttribute(GenerateSerializableTypes, generatedType, contractCodeDomInfo);
        }
 
        private void ExportXmlDataContract(XmlDataContract xmlDataContract, ContractCodeDomInfo contractCodeDomInfo)
        {
            GenerateType(xmlDataContract, contractCodeDomInfo);
            if (contractCodeDomInfo.ReferencedTypeExists)
                return;
 
            CodeTypeDeclaration type = contractCodeDomInfo.TypeDeclaration;
            if (SupportsPartialTypes)
                type.IsPartial = true;
            if (xmlDataContract.IsValueType)
                type.IsStruct = true;
            else
            {
                type.IsClass = true;
                type.BaseTypes.Add(Globals.TypeOfObject);
            }
            AddSerializableAttribute(GenerateSerializableTypes, type, contractCodeDomInfo);
 
            type.BaseTypes.Add(DataContract.GetClrTypeFullName(Globals.TypeOfIXmlSerializable));
 
            type.Members.Add(NodeArrayField);
            type.Members.Add(NodeArrayProperty);
            type.Members.Add(ReadXmlMethod);
            type.Members.Add(WriteXmlMethod);
            type.Members.Add(GetSchemaMethod);
            if (xmlDataContract.IsAnonymous && !xmlDataContract.HasRoot)
            {
                type.CustomAttributes.Add(new CodeAttributeDeclaration(
                    DataContract.GetClrTypeFullName(Globals.TypeOfXmlSchemaProviderAttribute),
                    new CodeAttributeArgument(NullReference),
                    new CodeAttributeArgument(Globals.IsAnyProperty, new CodePrimitiveExpression(true)))
                );
            }
            else
            {
                type.CustomAttributes.Add(new CodeAttributeDeclaration(
                    DataContract.GetClrTypeFullName(Globals.TypeOfXmlSchemaProviderAttribute),
                    new CodeAttributeArgument(new CodePrimitiveExpression(Globals.ExportSchemaMethod)))
                );
 
                CodeMemberField typeNameField = new CodeMemberField(Globals.TypeOfXmlQualifiedName, typeNameFieldName);
                typeNameField.Attributes |= MemberAttributes.Static | MemberAttributes.Private;
                XmlQualifiedName typeName = xmlDataContract.IsAnonymous
                    ? SchemaImporter.ImportActualType(xmlDataContract.XsdType.Annotation, xmlDataContract.StableName, xmlDataContract.StableName)
                    : xmlDataContract.StableName;
                typeNameField.InitExpression = new CodeObjectCreateExpression(Globals.TypeOfXmlQualifiedName, new CodePrimitiveExpression(typeName.Name), new CodePrimitiveExpression(typeName.Namespace));
                type.Members.Add(typeNameField);
 
                type.Members.Add(GetSchemaStaticMethod);
 
                bool isElementNameDifferent =
                    (xmlDataContract.TopLevelElementName != null && xmlDataContract.TopLevelElementName.Value != xmlDataContract.StableName.Name) ||
                    (xmlDataContract.TopLevelElementNamespace != null && xmlDataContract.TopLevelElementNamespace.Value != xmlDataContract.StableName.Namespace);
                if (isElementNameDifferent || xmlDataContract.IsTopLevelElementNullable == false)
                {
                    CodeAttributeDeclaration xmlRootAttribute = new CodeAttributeDeclaration(DataContract.GetClrTypeFullName(Globals.TypeOfXmlRootAttribute));
                    if (isElementNameDifferent)
                    {
                        if (xmlDataContract.TopLevelElementName != null)
                        {
                            xmlRootAttribute.Arguments.Add(new CodeAttributeArgument("ElementName", new CodePrimitiveExpression(xmlDataContract.TopLevelElementName.Value)));
                        }
                        if (xmlDataContract.TopLevelElementNamespace != null)
                        {
                            xmlRootAttribute.Arguments.Add(new CodeAttributeArgument("Namespace", new CodePrimitiveExpression(xmlDataContract.TopLevelElementNamespace.Value)));
                        }
                    }
                    if (xmlDataContract.IsTopLevelElementNullable == false)
                        xmlRootAttribute.Arguments.Add(new CodeAttributeArgument("IsNullable", new CodePrimitiveExpression(false)));
                    type.CustomAttributes.Add(xmlRootAttribute);
                }
            }
            AddPropertyChangedNotifier(contractCodeDomInfo, type.IsStruct);
        }
 
        CodeNamespace GetCodeNamespace(string clrNamespace, string dataContractNamespace, ContractCodeDomInfo contractCodeDomInfo)
        {
            if (contractCodeDomInfo.CodeNamespace != null)
                return contractCodeDomInfo.CodeNamespace;
 
            CodeNamespaceCollection codeNamespaceCollection = codeCompileUnit.Namespaces;
            foreach (CodeNamespace ns in codeNamespaceCollection)
            {
                if (ns.Name == clrNamespace)
                {
                    contractCodeDomInfo.CodeNamespace = ns;
                    return ns;
                }
            }
 
            CodeNamespace codeNamespace = new CodeNamespace(clrNamespace);
            codeNamespaceCollection.Add(codeNamespace);
 
            if (CanDeclareAssemblyAttribute(contractCodeDomInfo)
                && NeedsExplicitNamespace(dataContractNamespace, clrNamespace))
            {
                CodeAttributeDeclaration namespaceAttribute = new CodeAttributeDeclaration(DataContract.GetClrTypeFullName(Globals.TypeOfContractNamespaceAttribute));
                namespaceAttribute.Arguments.Add(new CodeAttributeArgument(new CodePrimitiveExpression(dataContractNamespace)));
                namespaceAttribute.Arguments.Add(new CodeAttributeArgument(Globals.ClrNamespaceProperty, new CodePrimitiveExpression(clrNamespace)));
                codeCompileUnit.AssemblyCustomAttributes.Add(namespaceAttribute);
            }
            contractCodeDomInfo.CodeNamespace = codeNamespace;
            return codeNamespace;
        }
 
        string GetMemberName(string memberName, ContractCodeDomInfo contractCodeDomInfo)
        {
            memberName = GetClrIdentifier(memberName, Globals.DefaultGeneratedMember);
 
            if (memberName == contractCodeDomInfo.TypeDeclaration.Name)
                memberName = AppendToValidClrIdentifier(memberName, Globals.DefaultMemberSuffix);
 
            if (contractCodeDomInfo.GetMemberNames().ContainsKey(memberName))
            {
                string uniqueMemberName = null;
                for (int i = 1;; i++)
                {
                    uniqueMemberName = AppendToValidClrIdentifier(memberName, i.ToString(NumberFormatInfo.InvariantInfo));
                    if (!contractCodeDomInfo.GetMemberNames().ContainsKey(uniqueMemberName))
                    {
                        memberName = uniqueMemberName;
                        break;
                    }
                }
            }
 
            contractCodeDomInfo.GetMemberNames().Add(memberName, null);
            return memberName;
        }
 
        void AddBaseMemberNames(ContractCodeDomInfo baseContractCodeDomInfo, ContractCodeDomInfo contractCodeDomInfo)
        {
            if (!baseContractCodeDomInfo.ReferencedTypeExists)
            {
                Dictionary<string, object> baseMemberNames = baseContractCodeDomInfo.GetMemberNames();
                Dictionary<string, object> memberNames = contractCodeDomInfo.GetMemberNames();
                foreach (KeyValuePair<string, object> pair in baseMemberNames)
                {
                    memberNames.Add(pair.Key, pair.Value);
                }
            }
        }
 
        [Fx.Tag.SecurityNote(Critical = "Critical because it calls the CodeGenerator.IsValidLanguageIndependentIdentifier(..) method that has a LinkDemand.",
            Safe = "Safe because it doesn't leak security sensitive information.")]
        [SecuritySafeCritical]
        static string GetClrIdentifier(string identifier, string defaultIdentifier)
        {
            if (identifier.Length <= MaxIdentifierLength && System.CodeDom.Compiler.CodeGenerator.IsValidLanguageIndependentIdentifier(identifier))
                return identifier;
 
            bool isStart = true;
            StringBuilder builder = new StringBuilder();
            for (int i = 0; i < identifier.Length && builder.Length < MaxIdentifierLength; i++)
            {
                char c = identifier[i];
                if (IsValid(c))
                {
                    if (isStart && !IsValidStart(c))
                        builder.Append("_");
                    builder.Append(c);
                    isStart = false;
                }
            }
            if (builder.Length == 0)
                return defaultIdentifier;
 
            return builder.ToString();
        }
 
        static string AppendToValidClrIdentifier(string identifier, string appendString)
        {
            int availableLength = MaxIdentifierLength - identifier.Length;
            int requiredLength = appendString.Length;
            if (availableLength < requiredLength)
                identifier = identifier.Substring(0, MaxIdentifierLength - requiredLength);
            identifier += appendString;
            return identifier;
        }
 
        string GetClrNamespace(DataContract dataContract, ContractCodeDomInfo contractCodeDomInfo)
        {
            string clrNamespace = contractCodeDomInfo.ClrNamespace;
            bool usesWildcardNamespace = false;
            if (clrNamespace == null)
            {
                if (!Namespaces.TryGetValue(dataContract.StableName.Namespace, out clrNamespace))
                {
                    if (Namespaces.TryGetValue(wildcardNamespaceMapping, out clrNamespace))
                    {
                        usesWildcardNamespace = true;
                    }
                    else
                    {
                        clrNamespace = GetClrNamespace(dataContract.StableName.Namespace);
                        if (ClrNamespaces.ContainsKey(clrNamespace))
                        {
                            string uniqueNamespace = null;
                            for (int i = 1;; i++)
                            {
                                uniqueNamespace = ((clrNamespace.Length == 0) ? Globals.DefaultClrNamespace : clrNamespace) + i.ToString(NumberFormatInfo.InvariantInfo);
                                if (!ClrNamespaces.ContainsKey(uniqueNamespace))
                                {
                                    clrNamespace = uniqueNamespace;
                                    break;
                                }
                            }
                        }
                        AddNamespacePair(dataContract.StableName.Namespace, clrNamespace);
                    }
                }
                contractCodeDomInfo.ClrNamespace = clrNamespace;
                contractCodeDomInfo.UsesWildcardNamespace = usesWildcardNamespace;
            }
            return clrNamespace;
        }
 
        void AddNamespacePair(string dataContractNamespace, string clrNamespace)
        {
            Namespaces.Add(dataContractNamespace, clrNamespace);
            ClrNamespaces.Add(clrNamespace, dataContractNamespace);
        }
 
        void AddImportStatement(string clrNamespace, CodeNamespace codeNamespace)
        {
            if (clrNamespace == codeNamespace.Name)
                return;
 
            CodeNamespaceImportCollection importCollection = codeNamespace.Imports;
            foreach (CodeNamespaceImport import in importCollection)
            {
                if (import.Namespace == clrNamespace)
                    return;
            }
 
            importCollection.Add(new CodeNamespaceImport(clrNamespace));
        }
 
        static string GetClrNamespace(string dataContractNamespace)
        {
            if (dataContractNamespace == null || dataContractNamespace.Length == 0)
                return String.Empty;
 
            Uri uri = null;
            StringBuilder builder = new StringBuilder();
            if (Uri.TryCreate(dataContractNamespace, UriKind.RelativeOrAbsolute, out uri))
            {
                Dictionary<string, object> fragments = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
                if (!uri.IsAbsoluteUri)
                    AddToNamespace(builder, uri.OriginalString, fragments);
                else
                {
                    string uriString = uri.AbsoluteUri;
                    if (uriString.StartsWith(Globals.DataContractXsdBaseNamespace, StringComparison.Ordinal))
                        AddToNamespace(builder, uriString.Substring(Globals.DataContractXsdBaseNamespace.Length), fragments);
                    else
                    {
                        string host = uri.Host;
                        if (host != null)
                            AddToNamespace(builder, host, fragments);
                        string path = uri.PathAndQuery;
                        if (path != null)
                            AddToNamespace(builder, path, fragments);
                    }
                }
            }
 
            if (builder.Length == 0)
                return String.Empty;
 
            int length = builder.Length;
            if (builder[builder.Length - 1] == '.')
                length--;
            length = Math.Min(MaxIdentifierLength, length);
 
            return builder.ToString(0, length);
        }
 
        static void AddToNamespace(StringBuilder builder, string fragment, Dictionary<string, object> fragments)
        {
            if (fragment == null)
                return;
            bool isStart = true;
            int fragmentOffset = builder.Length;
            int fragmentLength = 0;
 
            for (int i = 0; i < fragment.Length && builder.Length < MaxIdentifierLength; i++)
            {
                char c = fragment[i];
 
                if (IsValid(c))
                {
                    if (isStart && !IsValidStart(c))
                        builder.Append("_");
                    builder.Append(c);
                    fragmentLength++;
                    isStart = false;
                }
                else if ((c == '.' || c == '/' || c == ':') && (builder.Length == 1
                    || (builder.Length > 1 && builder[builder.Length - 1] != '.')))
                {
                    AddNamespaceFragment(builder, fragmentOffset, fragmentLength, fragments);
                    builder.Append('.');
                    fragmentOffset = builder.Length;
                    fragmentLength = 0;
                    isStart = true;
                }
            }
            AddNamespaceFragment(builder, fragmentOffset, fragmentLength, fragments);
        }
 
        static void AddNamespaceFragment(StringBuilder builder, int fragmentOffset,
            int fragmentLength, Dictionary<string, object> fragments)
        {
            if (fragmentLength == 0)
                return;
 
            string nsFragment = builder.ToString(fragmentOffset, fragmentLength);
            if (fragments.ContainsKey(nsFragment))
            {
                for (int i = 1;; i++)
                {
                    string uniquifier = i.ToString(NumberFormatInfo.InvariantInfo);
                    string uniqueNsFragment = AppendToValidClrIdentifier(nsFragment, uniquifier);
                    if (!fragments.ContainsKey(uniqueNsFragment))
                    {
                        builder.Append(uniquifier);
                        nsFragment = uniqueNsFragment;
                        break;
                    }
                    if (i == Int32.MaxValue)
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.CannotComputeUniqueName, nsFragment)));
                }
            }
            fragments.Add(nsFragment, null);
        }
 
        static bool IsValidStart(char c)
        {
            return (Char.GetUnicodeCategory(c) != UnicodeCategory.DecimalDigitNumber);
        }
 
        static bool IsValid(char c)
        {
            UnicodeCategory uc = Char.GetUnicodeCategory(c);
 
            // each char must be Lu, Ll, Lt, Lm, Lo, Nd, Mn, Mc, Pc
 
            switch (uc)
            {
                case UnicodeCategory.UppercaseLetter:        // Lu
                case UnicodeCategory.LowercaseLetter:        // Ll
                case UnicodeCategory.TitlecaseLetter:        // Lt
                case UnicodeCategory.ModifierLetter:         // Lm
                case UnicodeCategory.OtherLetter:            // Lo
                case UnicodeCategory.DecimalDigitNumber:     // Nd
                case UnicodeCategory.NonSpacingMark:         // Mn
                case UnicodeCategory.SpacingCombiningMark:   // Mc
                case UnicodeCategory.ConnectorPunctuation:   // Pc
                    return true;
                default:
                    return false;
            }
        }
 
        CodeTypeReference CodeTypeIPropertyChange
        {
            get { return GetCodeTypeReference(typeof(System.ComponentModel.INotifyPropertyChanged)); }
        }
 
        CodeThisReferenceExpression ThisReference
        {
            get { return new CodeThisReferenceExpression(); }
        }
 
        CodePrimitiveExpression NullReference
        {
            get { return new CodePrimitiveExpression(null); }
        }
 
        CodeParameterDeclarationExpression SerializationInfoParameter
        {
            get { return new CodeParameterDeclarationExpression(GetCodeTypeReference(Globals.TypeOfSerializationInfo), Globals.SerializationInfoFieldName); }
        }
 
        CodeParameterDeclarationExpression StreamingContextParameter
        {
            get { return new CodeParameterDeclarationExpression(GetCodeTypeReference(Globals.TypeOfStreamingContext), Globals.ContextFieldName); }
        }
 
        CodeAttributeDeclaration SerializableAttribute
        {
            get { return new CodeAttributeDeclaration(GetCodeTypeReference(Globals.TypeOfSerializableAttribute)); }
        }
 
        CodeMemberProperty NodeArrayProperty
        {
            get
            {
                return CreateProperty(GetCodeTypeReference(Globals.TypeOfXmlNodeArray), Globals.NodeArrayPropertyName, Globals.NodeArrayFieldName, false/*isValueType*/);
            }
        }
 
        CodeMemberField NodeArrayField
        {
            get
            {
                CodeMemberField nodeArrayField = new CodeMemberField();
                nodeArrayField.Type = GetCodeTypeReference(Globals.TypeOfXmlNodeArray);
                nodeArrayField.Name = Globals.NodeArrayFieldName;
                nodeArrayField.Attributes = MemberAttributes.Private;
                return nodeArrayField;
            }
        }
        CodeMemberMethod ReadXmlMethod
        {
            get
            {
                CodeMemberMethod readXmlMethod = new CodeMemberMethod();
                readXmlMethod.Name = "ReadXml";
                CodeParameterDeclarationExpression readerArg = new CodeParameterDeclarationExpression(typeof(XmlReader), "reader");
                readXmlMethod.Parameters.Add(readerArg);
                readXmlMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final;
                readXmlMethod.ImplementationTypes.Add(Globals.TypeOfIXmlSerializable);
                CodeAssignStatement setNode = new CodeAssignStatement();
                setNode.Left = new CodeFieldReferenceExpression(ThisReference, Globals.NodeArrayFieldName);
                setNode.Right = new CodeMethodInvokeExpression(
                                      new CodeTypeReferenceExpression(GetCodeTypeReference(Globals.TypeOfXmlSerializableServices)),
                                      XmlSerializableServices.ReadNodesMethodName,
                                      new CodeArgumentReferenceExpression(readerArg.Name)
                                    );
                readXmlMethod.Statements.Add(setNode);
                return readXmlMethod;
            }
        }
        CodeMemberMethod WriteXmlMethod
        {
            get
            {
                CodeMemberMethod writeXmlMethod = new CodeMemberMethod();
                writeXmlMethod.Name = "WriteXml";
                CodeParameterDeclarationExpression writerArg = new CodeParameterDeclarationExpression(typeof(XmlWriter), "writer");
                writeXmlMethod.Parameters.Add(writerArg);
                writeXmlMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final;
                writeXmlMethod.ImplementationTypes.Add(Globals.TypeOfIXmlSerializable);
                writeXmlMethod.Statements.Add(
                    new CodeMethodInvokeExpression(
                        new CodeTypeReferenceExpression(GetCodeTypeReference(Globals.TypeOfXmlSerializableServices)),
                        XmlSerializableServices.WriteNodesMethodName,
                        new CodeArgumentReferenceExpression(writerArg.Name),
                        new CodePropertyReferenceExpression(ThisReference, Globals.NodeArrayPropertyName)
                    )
                );
                return writeXmlMethod;
            }
        }
 
        CodeMemberMethod GetSchemaMethod
        {
            get
            {
                CodeMemberMethod getSchemaMethod = new CodeMemberMethod();
                getSchemaMethod.Name = "GetSchema";
                getSchemaMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final;
                getSchemaMethod.ImplementationTypes.Add(Globals.TypeOfIXmlSerializable);
                getSchemaMethod.ReturnType = GetCodeTypeReference(typeof(XmlSchema));
                getSchemaMethod.Statements.Add(new CodeMethodReturnStatement(NullReference));
                return getSchemaMethod;
            }
        }
 
        CodeMemberMethod GetSchemaStaticMethod
        {
            get
            {
                CodeMemberMethod getSchemaStaticMethod = new CodeMemberMethod();
                getSchemaStaticMethod.Name = Globals.ExportSchemaMethod;
                getSchemaStaticMethod.ReturnType = GetCodeTypeReference(Globals.TypeOfXmlQualifiedName);
                CodeParameterDeclarationExpression paramDeclaration = new CodeParameterDeclarationExpression(Globals.TypeOfXmlSchemaSet, "schemas");
                getSchemaStaticMethod.Parameters.Add(paramDeclaration);
                getSchemaStaticMethod.Attributes = MemberAttributes.Static | MemberAttributes.Public;
                getSchemaStaticMethod.Statements.Add(
                    new CodeMethodInvokeExpression(
                        new CodeTypeReferenceExpression(GetCodeTypeReference(typeof(XmlSerializableServices))),
                        XmlSerializableServices.AddDefaultSchemaMethodName,
                        new CodeArgumentReferenceExpression(paramDeclaration.Name),
                        new CodeFieldReferenceExpression(null, typeNameFieldName)
                    )
                );
                getSchemaStaticMethod.Statements.Add(
                    new CodeMethodReturnStatement(
                        new CodeFieldReferenceExpression(null, typeNameFieldName)
                    )
                );
                return getSchemaStaticMethod;
            }
        }
 
        CodeConstructor ISerializableBaseConstructor
        {
            get
            {
                CodeConstructor baseConstructor = new CodeConstructor();
                baseConstructor.Attributes = MemberAttributes.Public;
                baseConstructor.Parameters.Add(SerializationInfoParameter);
                baseConstructor.Parameters.Add(StreamingContextParameter);
                CodeAssignStatement setObjectData = new CodeAssignStatement();
                setObjectData.Left = new CodePropertyReferenceExpression(ThisReference, Globals.SerializationInfoFieldName);
                setObjectData.Right = new CodeArgumentReferenceExpression(Globals.SerializationInfoFieldName);
                baseConstructor.Statements.Add(setObjectData);
                // Special-cased check for vb here since CodeGeneratorOptions does not provide information indicating that VB cannot initialize event member
                if (EnableDataBinding && SupportsDeclareEvents && String.CompareOrdinal(FileExtension, "vb") != 0)
                {
                    baseConstructor.Statements.Add(new CodeAssignStatement(new CodePropertyReferenceExpression(ThisReference, PropertyChangedEvent.Name), NullReference));
                }
                return baseConstructor;
            }
        }
 
        CodeConstructor ISerializableDerivedConstructor
        {
            get
            {
                CodeConstructor derivedConstructor = new CodeConstructor();
                derivedConstructor.Attributes = MemberAttributes.Public;
                derivedConstructor.Parameters.Add(SerializationInfoParameter);
                derivedConstructor.Parameters.Add(StreamingContextParameter);
                derivedConstructor.BaseConstructorArgs.Add(new CodeVariableReferenceExpression(Globals.SerializationInfoFieldName));
                derivedConstructor.BaseConstructorArgs.Add(new CodeVariableReferenceExpression(Globals.ContextFieldName));
                return derivedConstructor;
            }
        }
 
        CodeMemberField SerializationInfoField
        {
            get
            {
                CodeMemberField serializationInfoField = new CodeMemberField();
                serializationInfoField.Type = GetCodeTypeReference(Globals.TypeOfSerializationInfo);
                serializationInfoField.Name = Globals.SerializationInfoFieldName;
                serializationInfoField.Attributes = MemberAttributes.Private;
                return serializationInfoField;
            }
        }
 
        CodeMemberProperty SerializationInfoProperty
        {
            get
            {
                return CreateProperty(GetCodeTypeReference(Globals.TypeOfSerializationInfo), Globals.SerializationInfoPropertyName, Globals.SerializationInfoFieldName, false/*isValueType*/);
            }
        }
 
        CodeMemberMethod GetObjectDataMethod
        {
            get
            {
                CodeMemberMethod getObjectDataMethod = new CodeMemberMethod();
                getObjectDataMethod.Name = Globals.GetObjectDataMethodName;
                getObjectDataMethod.Parameters.Add(SerializationInfoParameter);
                getObjectDataMethod.Parameters.Add(StreamingContextParameter);
                getObjectDataMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final;
                getObjectDataMethod.ImplementationTypes.Add(Globals.TypeOfISerializable);
 
                // Generates: if (this.SerializationInfo == null) return;
                CodeConditionStatement returnIfNull = new CodeConditionStatement();
                returnIfNull.Condition = new CodeBinaryOperatorExpression(
                    new CodePropertyReferenceExpression(ThisReference, Globals.SerializationInfoPropertyName),
                    CodeBinaryOperatorType.IdentityEquality,
                    NullReference);
                returnIfNull.TrueStatements.Add(new CodeMethodReturnStatement());
 
                // Generates: SerializationInfoEnumerator enumerator = this.SerializationInfo.GetEnumerator();
                CodeVariableDeclarationStatement getEnumerator = new CodeVariableDeclarationStatement();
                getEnumerator.Type = GetCodeTypeReference(Globals.TypeOfSerializationInfoEnumerator);
                getEnumerator.Name = Globals.EnumeratorFieldName;
                getEnumerator.InitExpression = new CodeMethodInvokeExpression(
                    new CodePropertyReferenceExpression(ThisReference, Globals.SerializationInfoPropertyName),
                    Globals.GetEnumeratorMethodName);
 
                //Generates: SerializationEntry entry = enumerator.Current;
                CodeVariableDeclarationStatement getCurrent = new CodeVariableDeclarationStatement();
                getCurrent.Type = GetCodeTypeReference(Globals.TypeOfSerializationEntry);
                getCurrent.Name = Globals.SerializationEntryFieldName;
                getCurrent.InitExpression = new CodePropertyReferenceExpression(
                    new CodeVariableReferenceExpression(Globals.EnumeratorFieldName),
                    Globals.CurrentPropertyName);
 
                //Generates: info.AddValue(entry.Name, entry.Value);
                CodeExpressionStatement addValue = new CodeExpressionStatement();
                CodePropertyReferenceExpression getCurrentName = new CodePropertyReferenceExpression(
                    new CodeVariableReferenceExpression(Globals.SerializationEntryFieldName),
                    Globals.NameProperty);
                CodePropertyReferenceExpression getCurrentValue = new CodePropertyReferenceExpression(
                    new CodeVariableReferenceExpression(Globals.SerializationEntryFieldName),
                    Globals.ValueProperty);
                addValue.Expression = new CodeMethodInvokeExpression(
                    new CodeArgumentReferenceExpression(Globals.SerializationInfoFieldName),
                    Globals.AddValueMethodName,
                    new CodeExpression[] { getCurrentName, getCurrentValue });
 
                //Generates: for (; enumerator.MoveNext(); )
                CodeIterationStatement loop = new CodeIterationStatement();
                loop.TestExpression = new CodeMethodInvokeExpression(
                    new CodeVariableReferenceExpression(Globals.EnumeratorFieldName),
                    Globals.MoveNextMethodName);
                loop.InitStatement = loop.IncrementStatement = new CodeSnippetStatement(String.Empty);
                loop.Statements.Add(getCurrent);
                loop.Statements.Add(addValue);
 
                getObjectDataMethod.Statements.Add(returnIfNull);
                getObjectDataMethod.Statements.Add(getEnumerator);
                getObjectDataMethod.Statements.Add(loop);
 
                return getObjectDataMethod;
            }
        }
 
        CodeMemberField ExtensionDataObjectField
        {
            get
            {
                CodeMemberField extensionDataObjectField = new CodeMemberField();
                extensionDataObjectField.Type = GetCodeTypeReference(Globals.TypeOfExtensionDataObject);
                extensionDataObjectField.Name = Globals.ExtensionDataObjectFieldName;
                extensionDataObjectField.Attributes = MemberAttributes.Private;
                return extensionDataObjectField;
            }
        }
 
        CodeMemberProperty ExtensionDataObjectProperty
        {
            get
            {
                CodeMemberProperty extensionDataObjectProperty = new CodeMemberProperty();
                extensionDataObjectProperty.Type = GetCodeTypeReference(Globals.TypeOfExtensionDataObject);
                extensionDataObjectProperty.Name = Globals.ExtensionDataObjectPropertyName;
                extensionDataObjectProperty.Attributes = MemberAttributes.Public | MemberAttributes.Final;
                extensionDataObjectProperty.ImplementationTypes.Add(Globals.TypeOfIExtensibleDataObject);
 
                CodeMethodReturnStatement propertyGet = new CodeMethodReturnStatement();
                propertyGet.Expression = new CodeFieldReferenceExpression(ThisReference, Globals.ExtensionDataObjectFieldName);
                extensionDataObjectProperty.GetStatements.Add(propertyGet);
 
                CodeAssignStatement propertySet = new CodeAssignStatement();
                propertySet.Left = new CodeFieldReferenceExpression(ThisReference, Globals.ExtensionDataObjectFieldName);
                propertySet.Right = new CodePropertySetValueReferenceExpression();
                extensionDataObjectProperty.SetStatements.Add(propertySet);
 
                return extensionDataObjectProperty;
            }
        }
 
        CodeMemberMethod RaisePropertyChangedEventMethod
        {
            get
            {
                CodeMemberMethod raisePropertyChangedEventMethod = new CodeMemberMethod();
                raisePropertyChangedEventMethod.Name = "RaisePropertyChanged";
                raisePropertyChangedEventMethod.Attributes = MemberAttributes.Final;
                CodeArgumentReferenceExpression propertyName = new CodeArgumentReferenceExpression("propertyName");
                raisePropertyChangedEventMethod.Parameters.Add(new CodeParameterDeclarationExpression(typeof(string), propertyName.ParameterName));
                CodeVariableReferenceExpression propertyChanged = new CodeVariableReferenceExpression("propertyChanged");
                raisePropertyChangedEventMethod.Statements.Add(new CodeVariableDeclarationStatement(typeof(PropertyChangedEventHandler), propertyChanged.VariableName, new CodeEventReferenceExpression(ThisReference, PropertyChangedEvent.Name)));
                CodeConditionStatement ifStatement = new CodeConditionStatement(new CodeBinaryOperatorExpression(propertyChanged, CodeBinaryOperatorType.IdentityInequality, NullReference));
                raisePropertyChangedEventMethod.Statements.Add(ifStatement);
                ifStatement.TrueStatements.Add(new CodeDelegateInvokeExpression(propertyChanged, ThisReference, new CodeObjectCreateExpression(typeof(PropertyChangedEventArgs), propertyName)));
                return raisePropertyChangedEventMethod;
            }
        }
 
        CodeMemberEvent PropertyChangedEvent
        {
            get
            {
                CodeMemberEvent propertyChangedEvent = new CodeMemberEvent();
                propertyChangedEvent.Attributes = MemberAttributes.Public;
                propertyChangedEvent.Name = "PropertyChanged";
                propertyChangedEvent.Type = GetCodeTypeReference(typeof(PropertyChangedEventHandler));
                propertyChangedEvent.ImplementationTypes.Add(Globals.TypeOfIPropertyChange);
                return propertyChangedEvent;
            }
        }
 
        CodeMemberProperty CreateProperty(CodeTypeReference type, string propertyName, string fieldName, bool isValueType)
        {
            return CreateProperty(type, propertyName, fieldName, isValueType, EnableDataBinding && SupportsDeclareEvents);
        }
 
        CodeMemberProperty CreateProperty(CodeTypeReference type, string propertyName, string fieldName, bool isValueType, bool raisePropertyChanged)
        {
            CodeMemberProperty property = new CodeMemberProperty();
            property.Type = type;
            property.Name = propertyName;
            property.Attributes = MemberAttributes.Final;
            if (GenerateInternalTypes)
                property.Attributes |= MemberAttributes.Assembly;
            else
                property.Attributes |= MemberAttributes.Public;
 
            CodeMethodReturnStatement propertyGet = new CodeMethodReturnStatement();
            propertyGet.Expression = new CodeFieldReferenceExpression(ThisReference, fieldName);
            property.GetStatements.Add(propertyGet);
 
            CodeAssignStatement propertySet = new CodeAssignStatement();
            propertySet.Left = new CodeFieldReferenceExpression(ThisReference, fieldName);
            propertySet.Right = new CodePropertySetValueReferenceExpression();
            if (raisePropertyChanged)
            {
                CodeConditionStatement ifStatement = new CodeConditionStatement();
                CodeExpression left = new CodeFieldReferenceExpression(ThisReference, fieldName);
                CodeExpression right = new CodePropertySetValueReferenceExpression();
                if (!isValueType)
                {
                    left = new CodeMethodInvokeExpression(new CodeTypeReferenceExpression(Globals.TypeOfObject),
                        "ReferenceEquals", new CodeExpression[] { left, right });
                }
                else
                {
                    left = new CodeMethodInvokeExpression(left, "Equals", new CodeExpression[] { right });
                }
                right = new CodePrimitiveExpression(true);
                ifStatement.Condition = new CodeBinaryOperatorExpression(left, CodeBinaryOperatorType.IdentityInequality, right);
                ifStatement.TrueStatements.Add(propertySet);
                ifStatement.TrueStatements.Add(new CodeMethodInvokeExpression(ThisReference, RaisePropertyChangedEventMethod.Name, new CodePrimitiveExpression(propertyName)));
                property.SetStatements.Add(ifStatement);
            }
            else
                property.SetStatements.Add(propertySet);
            return property;
        }
    }
}