File: System\Xml\Serialization\XmlSerializationWriterILGen.cs
Project: ndp\fx\src\Xml\System.Xml.csproj (System.Xml)
//------------------------------------------------------------------------------
// <copyright file="XmlSerializationWriterILGen.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
// <owner current="true" primary="true">Microsoft</owner>                                                                
//------------------------------------------------------------------------------
 
namespace System.Xml.Serialization {
 
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Globalization;
    using System.Reflection;
    using System.Reflection.Emit;
    using System.Text;
    using System.Xml.Schema;
 
    internal class XmlSerializationWriterILGen : XmlSerializationILGen {
 
        internal XmlSerializationWriterILGen(TypeScope[] scopes, string access, string className)
            : base(scopes, access, className) {
        }
 
        internal void GenerateBegin() {
            this.typeBuilder = CodeGenerator.CreateTypeBuilder(
                ModuleBuilder,
                ClassName,
                TypeAttributes | TypeAttributes.BeforeFieldInit,
                typeof(XmlSerializationWriter),
                CodeGenerator.EmptyTypeArray);
 
            foreach (TypeScope scope in Scopes) {
                foreach (TypeMapping mapping in scope.TypeMappings) {
                    if (mapping is StructMapping || mapping is EnumMapping) {
                        MethodNames.Add(mapping, NextMethodName(mapping.TypeDesc.Name));
                    }
                }
                RaCodeGen.WriteReflectionInit(scope);
            }
        }
 
        internal override void GenerateMethod(TypeMapping mapping) {
            if (GeneratedMethods.Contains(mapping))
                return;
 
            GeneratedMethods[mapping] = mapping;
            if (mapping is StructMapping) {
                WriteStructMethod((StructMapping)mapping);
            }
            else if (mapping is EnumMapping) {
                WriteEnumMethod((EnumMapping)mapping);
            }
        }
        internal Type GenerateEnd() {
            GenerateReferencedMethods();
            GenerateInitCallbacksMethod();
            this.typeBuilder.DefineDefaultConstructor(
                CodeGenerator.PublicMethodAttributes);
            return this.typeBuilder.CreateType();
        }
 
        internal string GenerateElement(XmlMapping xmlMapping) {
            if (!xmlMapping.IsWriteable)
                return null;
            if (!xmlMapping.GenerateSerializer)
                throw new ArgumentException(Res.GetString(Res.XmlInternalError), "xmlMapping");
            if (xmlMapping is XmlTypeMapping)
                return GenerateTypeElement((XmlTypeMapping)xmlMapping);
            else if (xmlMapping is XmlMembersMapping)
                return GenerateMembersElement((XmlMembersMapping)xmlMapping);
            else
                throw new ArgumentException(Res.GetString(Res.XmlInternalError), "xmlMapping");
        }
 
        void GenerateInitCallbacksMethod() {
            ilg = new CodeGenerator(this.typeBuilder);
            ilg.BeginMethod(typeof(void), "InitCallbacks", CodeGenerator.EmptyTypeArray, CodeGenerator.EmptyStringArray,
                CodeGenerator.ProtectedOverrideMethodAttributes);
            ilg.EndMethod();
        }
 
        void WriteQualifiedNameElement(string name, string ns, object defaultValue, SourceInfo source, bool nullable, TypeMapping mapping) {
            bool hasDefault = defaultValue != null && defaultValue != DBNull.Value;
            if (hasDefault) {
                throw CodeGenerator.NotSupported("XmlQualifiedName DefaultValue not supported.  Fail in WriteValue()");
            }
            List<Type> argTypes = new List<Type>();
            ilg.Ldarg(0);
            ilg.Ldstr(name);
            argTypes.Add(typeof(string));
            if (ns != null) {
                ilg.Ldstr(ns);
                argTypes.Add(typeof(string));
            }
            source.Load(mapping.TypeDesc.Type);
            argTypes.Add(mapping.TypeDesc.Type);
 
            MethodInfo XmlSerializationWriter_WriteXXX = typeof(XmlSerializationWriter).GetMethod(
                 nullable ? ("WriteNullableQualifiedNameLiteral") : "WriteElementQualifiedName",
                 CodeGenerator.InstanceBindingFlags,
                 null,
                 argTypes.ToArray(),
                 null
                 );
            ilg.Call(XmlSerializationWriter_WriteXXX);
 
            if (hasDefault) {
                throw CodeGenerator.NotSupported("XmlQualifiedName DefaultValue not supported.  Fail in WriteValue()");
            }
        }
 
        void WriteEnumValue(EnumMapping mapping, SourceInfo source, out Type returnType) {
            string methodName = ReferenceMapping(mapping);
 
#if DEBUG
            // use exception in the place of Debug.Assert to avoid throwing asserts from a server process such as aspnet_ewp.exe
            if (methodName == null) throw new InvalidOperationException(Res.GetString(Res.XmlInternalErrorMethod, mapping.TypeDesc.Name) + Environment.StackTrace);
#endif
 
            // For enum, its write method (eg. Write1_Gender) could be called multiple times
            // prior to its declaration.
            MethodBuilder methodBuilder = EnsureMethodBuilder(typeBuilder,
                    methodName,
                    CodeGenerator.PrivateMethodAttributes,
                    typeof(string),
                    new Type[] { mapping.TypeDesc.Type });
            ilg.Ldarg(0);
            source.Load(mapping.TypeDesc.Type);
            ilg.Call(methodBuilder);
            returnType = typeof(string);
        }
 
        void WritePrimitiveValue(TypeDesc typeDesc, SourceInfo source, out Type returnType) {
            if (typeDesc == StringTypeDesc || typeDesc.FormatterName == "String") {
                source.Load(typeDesc.Type);
                returnType = typeDesc.Type;
            }
            else {
                if (!typeDesc.HasCustomFormatter) {
                    Type argType = typeDesc.Type;
                    MethodInfo XmlConvert_ToString = typeof(XmlConvert).GetMethod(
                        "ToString",
                        CodeGenerator.StaticBindingFlags,
                        null,
                        new Type[] { argType },
                        null
                        );
                    source.Load(typeDesc.Type);
                    ilg.Call(XmlConvert_ToString);
                    returnType = XmlConvert_ToString.ReturnType;
                }
                else {
                    // Only these methods below that is non Static and need to ldarg("this") for Call.
                    BindingFlags bindingFlags = CodeGenerator.StaticBindingFlags;
                    if (typeDesc.FormatterName == "XmlQualifiedName") {
                        bindingFlags = CodeGenerator.InstanceBindingFlags;
                        ilg.Ldarg(0);
                    }
                    MethodInfo FromXXX = typeof(XmlSerializationWriter).GetMethod(
                           "From" + typeDesc.FormatterName,
                           bindingFlags,
                           null,
                           new Type[] { typeDesc.Type },
                           null
                           );
                    source.Load(typeDesc.Type);
                    ilg.Call(FromXXX);
                    returnType = FromXXX.ReturnType;
                }
            }
        }
 
        void WritePrimitive(string method, string name, string ns, object defaultValue, SourceInfo source, TypeMapping mapping, bool writeXsiType, bool isElement, bool isNullable) {
            TypeDesc typeDesc = mapping.TypeDesc;
            bool hasDefault = defaultValue != null && defaultValue != DBNull.Value && mapping.TypeDesc.HasDefaultSupport;
            if (hasDefault) {
                if (mapping is EnumMapping) {
#if DEBUG
                    // use exception in the place of Debug.Assert to avoid throwing asserts from a server process such as aspnet_ewp.exe
                    if (defaultValue.GetType() != typeof(string)) throw new InvalidOperationException(Res.GetString(Res.XmlInternalErrorDetails, name + " has invalid default type " + defaultValue.GetType().Name));
#endif
 
                    source.Load(mapping.TypeDesc.Type);
                    string enumDefaultValue = null;
                    if (((EnumMapping)mapping).IsFlags) {
                        string[] values = ((string)defaultValue).Split(null);
                        for (int i = 0; i < values.Length; i++) {
                            if (values[i] == null || values[i].Length == 0)
                                continue;
                            if (i > 0)
                                enumDefaultValue += ", ";
                            enumDefaultValue += values[i];
                        }
                    }
                    else {
                        enumDefaultValue = (string)defaultValue;
                    }
                    ilg.Ldc(Enum.Parse(mapping.TypeDesc.Type, enumDefaultValue, false));
                    ilg.If(Cmp.NotEqualTo); // " != "
                }
                else {
                    WriteCheckDefault(source, defaultValue, isNullable);
                }
            }
            List<Type> argTypes = new List<Type>();
            ilg.Ldarg(0);
            argTypes.Add(typeof(String));
            ilg.Ldstr(name);
            if (ns != null) {
                argTypes.Add(typeof(String));
                ilg.Ldstr(ns);
            }
            Type argType;
 
            if (mapping is EnumMapping) {
                WriteEnumValue((EnumMapping)mapping, source, out argType);
                argTypes.Add(argType);
            }
            else {
                WritePrimitiveValue(typeDesc, source, out argType);
                argTypes.Add(argType);
            }
 
            if (writeXsiType) {
                argTypes.Add(typeof(XmlQualifiedName));
                ConstructorInfo XmlQualifiedName_ctor = typeof(XmlQualifiedName).GetConstructor(
                    CodeGenerator.InstanceBindingFlags,
                    null,
                    new Type[] { typeof(String), typeof(String) },
                    null
                    );
                ilg.Ldstr(mapping.TypeName);
                ilg.Ldstr(mapping.Namespace);
                ilg.New(XmlQualifiedName_ctor);
            }
 
            MethodInfo XmlSerializationWriter_method = typeof(XmlSerializationWriter).GetMethod(
                   method,
                   CodeGenerator.InstanceBindingFlags,
                   null,
                   argTypes.ToArray(),
                   null
                   );
            ilg.Call(XmlSerializationWriter_method);
 
            if (hasDefault) {
                ilg.EndIf();
            }
        }
 
        void WriteTag(string methodName, string name, string ns) {
            MethodInfo XmlSerializationWriter_Method = typeof(XmlSerializationWriter).GetMethod(
                methodName,
                CodeGenerator.InstanceBindingFlags,
                null,
                new Type[] { typeof(String), typeof(String) },
                null
                );
            ilg.Ldarg(0);
            ilg.Ldstr(name);
            ilg.Ldstr(ns);
            ilg.Call(XmlSerializationWriter_Method);
        }
 
        void WriteTag(string methodName, string name, string ns, bool writePrefixed) {
            MethodInfo XmlSerializationWriter_Method = typeof(XmlSerializationWriter).GetMethod(
                methodName,
                CodeGenerator.InstanceBindingFlags,
                null,
                new Type[] { typeof(string), typeof(string), typeof(object), typeof(Boolean) },
                null
                );
            ilg.Ldarg(0);
            ilg.Ldstr(name);
            ilg.Ldstr(ns);
            ilg.Load(null);
            ilg.Ldc(writePrefixed);
            ilg.Call(XmlSerializationWriter_Method);
        }
 
        void WriteStartElement(string name, string ns, bool writePrefixed) {
            WriteTag("WriteStartElement", name, ns, writePrefixed);
        }
 
        void WriteEndElement() {
            MethodInfo XmlSerializationWriter_WriteEndElement = typeof(XmlSerializationWriter).GetMethod(
                "WriteEndElement",
                CodeGenerator.InstanceBindingFlags,
                null,
                CodeGenerator.EmptyTypeArray,
                null
                );
            ilg.Ldarg(0);
            ilg.Call(XmlSerializationWriter_WriteEndElement);
        }
        void WriteEndElement(string source) {
            MethodInfo XmlSerializationWriter_WriteEndElement = typeof(XmlSerializationWriter).GetMethod(
                "WriteEndElement",
                CodeGenerator.InstanceBindingFlags,
                null,
                new Type[] { typeof(Object) },
                null
                );
            object oVar = ilg.GetVariable(source);
            ilg.Ldarg(0);
            ilg.Load(oVar);
            ilg.ConvertValue(ilg.GetVariableType(oVar), typeof(Object));
            ilg.Call(XmlSerializationWriter_WriteEndElement);
        }
 
        void WriteLiteralNullTag(string name, string ns) {
            WriteTag("WriteNullTagLiteral", name, ns);
        }
 
        void WriteEmptyTag(string name, string ns) {
            WriteTag("WriteEmptyTag", name, ns);
        }
 
        string GenerateMembersElement(XmlMembersMapping xmlMembersMapping) {
            ElementAccessor element = xmlMembersMapping.Accessor;
            MembersMapping mapping = (MembersMapping)element.Mapping;
            bool hasWrapperElement = mapping.HasWrapperElement;
            bool writeAccessors = mapping.WriteAccessors;
            string methodName = NextMethodName(element.Name);
            ilg = new CodeGenerator(this.typeBuilder);
            ilg.BeginMethod(
                typeof(void),
                methodName,
                new Type[] { typeof(object[]) },
                new string[] { "p" },
                CodeGenerator.PublicMethodAttributes
                );
 
            MethodInfo XmlSerializationWriter_WriteStartDocument = typeof(XmlSerializationWriter).GetMethod(
                "WriteStartDocument",
                CodeGenerator.InstanceBindingFlags,
                null,
                CodeGenerator.EmptyTypeArray,
                null
                );
            ilg.Ldarg(0);
            ilg.Call(XmlSerializationWriter_WriteStartDocument);
 
            MethodInfo XmlSerializationWriter_TopLevelElement = typeof(XmlSerializationWriter).GetMethod(
                "TopLevelElement",
                CodeGenerator.InstanceBindingFlags,
                null,
                CodeGenerator.EmptyTypeArray,
                null
                );
            ilg.Ldarg(0);
            ilg.Call(XmlSerializationWriter_TopLevelElement);
 
            // in the top-level method add check for the parameters length, 
            // because visual basic does not have a concept of an <out> parameter it uses <ByRef> instead
            // so sometime we think that we have more parameters then supplied
            LocalBuilder pLengthLoc = ilg.DeclareLocal(typeof(int), "pLength");
            ilg.Ldarg("p");
            ilg.Ldlen();
            ilg.Stloc(pLengthLoc);
 
            if (hasWrapperElement) {
                WriteStartElement(element.Name, (element.Form == XmlSchemaForm.Qualified ? element.Namespace : ""), false);
 
                int xmlnsMember = FindXmlnsIndex(mapping.Members);
                if (xmlnsMember >= 0) {
                    MemberMapping member = mapping.Members[xmlnsMember];
                    string source = "((" + typeof(XmlSerializerNamespaces).FullName + ")p[" + xmlnsMember.ToString(CultureInfo.InvariantCulture) + "])";
 
                    ilg.Ldloc(pLengthLoc);
                    ilg.Ldc(xmlnsMember);
                    ilg.If(Cmp.GreaterThan);
                    WriteNamespaces(source);
                    ilg.EndIf();
                }
 
                for (int i = 0; i < mapping.Members.Length; i++) {
                    MemberMapping member = mapping.Members[i];
 
                    if (member.Attribute != null && !member.Ignore) {
                        SourceInfo source = new SourceInfo("p[" + i.ToString(CultureInfo.InvariantCulture) + "]", null, null, pLengthLoc.LocalType.GetElementType(), ilg);
 
                        SourceInfo specifiedSource = null;
                        int specifiedPosition = 0;
                        if (member.CheckSpecified != SpecifiedAccessor.None) {
                            string memberNameSpecified = member.Name + "Specified";
                            for (int j = 0; j < mapping.Members.Length; j++) {
                                if (mapping.Members[j].Name == memberNameSpecified) {
                                    specifiedSource = new SourceInfo("((bool)p[" + j.ToString(CultureInfo.InvariantCulture) + "])", null, null, typeof(bool), ilg);
                                    specifiedPosition = j;
                                    break;
                                }
                            }
                        }
 
                        ilg.Ldloc(pLengthLoc);
                        ilg.Ldc(i);
                        ilg.If(Cmp.GreaterThan);
 
                        if (specifiedSource != null) {
                            Label labelTrue = ilg.DefineLabel();
                            Label labelEnd = ilg.DefineLabel();
                            ilg.Ldloc(pLengthLoc);
                            ilg.Ldc(specifiedPosition);
                            ilg.Ble(labelTrue);
                            specifiedSource.Load(typeof(bool));
                            ilg.Br_S(labelEnd);
                            ilg.MarkLabel(labelTrue);
                            ilg.Ldc(true);
                            ilg.MarkLabel(labelEnd);
                            ilg.If();
                        }
 
                        WriteMember(source, member.Attribute, member.TypeDesc, "p");
 
                        if (specifiedSource != null) {
                            ilg.EndIf();
                        }
 
                        ilg.EndIf();
                    }
                }
            }
 
            for (int i = 0; i < mapping.Members.Length; i++) {
                MemberMapping member = mapping.Members[i];
                if (member.Xmlns != null)
                    continue;
                if (member.Ignore)
                    continue;
 
                SourceInfo specifiedSource = null;
                int specifiedPosition = 0;
                if (member.CheckSpecified != SpecifiedAccessor.None) {
                    string memberNameSpecified = member.Name + "Specified";
 
                    for (int j = 0; j < mapping.Members.Length; j++) {
                        if (mapping.Members[j].Name == memberNameSpecified) {
                            specifiedSource = new SourceInfo("((bool)p[" + j.ToString(CultureInfo.InvariantCulture) + "])", null, null, typeof(bool), ilg);
                            specifiedPosition = j;
                            break;
                        }
                    }
                }
 
                ilg.Ldloc(pLengthLoc);
                ilg.Ldc(i);
                ilg.If(Cmp.GreaterThan);
 
                if (specifiedSource != null) {
                    Label labelTrue = ilg.DefineLabel();
                    Label labelEnd = ilg.DefineLabel();
                    ilg.Ldloc(pLengthLoc);
                    ilg.Ldc(specifiedPosition);
                    ilg.Ble(labelTrue);
                    specifiedSource.Load(typeof(bool));
                    ilg.Br_S(labelEnd);
                    ilg.MarkLabel(labelTrue);
                    ilg.Ldc(true);
                    ilg.MarkLabel(labelEnd);
                    ilg.If();
                }
 
                string source = "p[" + i.ToString(CultureInfo.InvariantCulture) + "]";
                string enumSource = null;
                if (member.ChoiceIdentifier != null) {
                    for (int j = 0; j < mapping.Members.Length; j++) {
                        if (mapping.Members[j].Name == member.ChoiceIdentifier.MemberName) {
                            enumSource = "((" + mapping.Members[j].TypeDesc.CSharpName + ")p[" + j.ToString(CultureInfo.InvariantCulture) + "]" + ")";
                            break;
                        }
                    }
 
#if DEBUG
                    // use exception in the place of Debug.Assert to avoid throwing asserts from a server process such as aspnet_ewp.exe
                    if (enumSource == null) throw new InvalidOperationException(Res.GetString(Res.XmlInternalErrorDetails, "Can not find " + member.ChoiceIdentifier.MemberName + " in the members mapping."));
#endif
 
                }
 
                // override writeAccessors choice when we've written a wrapper element
                WriteMember(new SourceInfo(source, source, null, null, ilg), enumSource, member.ElementsSortedByDerivation, member.Text, member.ChoiceIdentifier, member.TypeDesc, writeAccessors || hasWrapperElement);
 
                if (specifiedSource != null) {
                    ilg.EndIf();
                }
 
                ilg.EndIf();
            }
 
            if (hasWrapperElement) {
                WriteEndElement();
            }
            ilg.EndMethod();
            return methodName;
        }
 
        string GenerateTypeElement(XmlTypeMapping xmlTypeMapping) {
            ElementAccessor element = xmlTypeMapping.Accessor;
            TypeMapping mapping = element.Mapping;
            string methodName = NextMethodName(element.Name);
            ilg = new CodeGenerator(this.typeBuilder);
            ilg.BeginMethod(
                typeof(void),
                methodName,
                new Type[] { typeof(object) },
                new string[] { "o" },
                CodeGenerator.PublicMethodAttributes
                );
 
            MethodInfo XmlSerializationWriter_WriteStartDocument = typeof(XmlSerializationWriter).GetMethod(
                "WriteStartDocument",
                CodeGenerator.InstanceBindingFlags,
                null,
                CodeGenerator.EmptyTypeArray,
                null
                );
            ilg.Ldarg(0);
            ilg.Call(XmlSerializationWriter_WriteStartDocument);
 
            ilg.If(ilg.GetArg("o"), Cmp.EqualTo, null);
            if (element.IsNullable) {
                WriteLiteralNullTag(element.Name, (element.Form == XmlSchemaForm.Qualified ? element.Namespace : ""));
            }
            else
                WriteEmptyTag(element.Name, (element.Form == XmlSchemaForm.Qualified ? element.Namespace : ""));
            ilg.GotoMethodEnd();
            ilg.EndIf();
 
            if (!mapping.TypeDesc.IsValueType && !mapping.TypeDesc.Type.IsPrimitive) {
                MethodInfo XmlSerializationWriter_TopLevelElement = typeof(XmlSerializationWriter).GetMethod(
                      "TopLevelElement",
                      CodeGenerator.InstanceBindingFlags,
                      null,
                      CodeGenerator.EmptyTypeArray,
                      null
                      );
                ilg.Ldarg(0);
                ilg.Call(XmlSerializationWriter_TopLevelElement);
            }
 
            WriteMember(new SourceInfo("o", "o", null, typeof(object), ilg), null, new ElementAccessor[] { element }, null, null, mapping.TypeDesc, true);
 
            ilg.EndMethod();
            return methodName;
        }
 
        string NextMethodName(string name) {
            return "Write" + (++NextMethodNumber).ToString(null, NumberFormatInfo.InvariantInfo) + "_" + CodeIdentifier.MakeValidInternal(name);
        }
 
        void WriteEnumMethod(EnumMapping mapping) {
            string methodName = (string)MethodNames[mapping];
            List<Type> argTypes = new List<Type>();
            List<string> argNames = new List<string>();
            argTypes.Add(mapping.TypeDesc.Type);
            argNames.Add("v");
            ilg = new CodeGenerator(this.typeBuilder);
            ilg.BeginMethod(
                typeof(string),
                GetMethodBuilder(methodName),
                argTypes.ToArray(),
                argNames.ToArray(),
                CodeGenerator.PrivateMethodAttributes);
            LocalBuilder sLoc = ilg.DeclareLocal(typeof(string), "s");
            ilg.Load(null);
            ilg.Stloc(sLoc);
            ConstantMapping[] constants = mapping.Constants;
 
            if (constants.Length > 0) {
                Hashtable values = new Hashtable();
                List<Label> caseLabels = new List<Label>();
                List<string> retValues = new List<string>();
                Label defaultLabel = ilg.DefineLabel();
                Label endSwitchLabel = ilg.DefineLabel();
                // This local is necessary; otherwise, it becomes if/else
                LocalBuilder localTmp = ilg.DeclareLocal(mapping.TypeDesc.Type, "localTmp");
                ilg.Ldarg("v");
                ilg.Stloc(localTmp);
                for (int i = 0; i < constants.Length; i++) {
                    ConstantMapping c = constants[i];
                    if (values[c.Value] == null) {
                        Label caseLabel = ilg.DefineLabel();
                        ilg.Ldloc(localTmp);
                        ilg.Ldc(Enum.ToObject(mapping.TypeDesc.Type, c.Value));
                        ilg.Beq(caseLabel);
                        caseLabels.Add(caseLabel);
                        retValues.Add(c.XmlName);
                        values.Add(c.Value, c.Value);
                    }
                }
 
 
                if (mapping.IsFlags) {
                    ilg.Br(defaultLabel);
                    for (int i = 0; i < caseLabels.Count; i++) {
                        ilg.MarkLabel(caseLabels[i]);
                        ilg.Ldc(retValues[i]);
                        ilg.Stloc(sLoc);
                        ilg.Br(endSwitchLabel);
                    }
                    ilg.MarkLabel(defaultLabel);
                    RaCodeGen.ILGenForEnumLongValue(ilg, "v");
                    LocalBuilder strArray = ilg.DeclareLocal(typeof(String[]), "strArray");
                    ilg.NewArray(typeof(String), constants.Length);
                    ilg.Stloc(strArray);
                    for (int i = 0; i < constants.Length; i++) {
                        ConstantMapping c = constants[i];
                        ilg.Ldloc(strArray);
                        ilg.Ldc(i);
                        ilg.Ldstr(c.XmlName);
                        ilg.Stelem(typeof(String));
                    }
                    ilg.Ldloc(strArray);
                    LocalBuilder longArray = ilg.DeclareLocal(typeof(long[]), "longArray");
                    ilg.NewArray(typeof(long), constants.Length);
                    ilg.Stloc(longArray);
 
                    for (int i = 0; i < constants.Length; i++) {
                        ConstantMapping c = constants[i];
                        ilg.Ldloc(longArray);
                        ilg.Ldc(i);
                        ilg.Ldc(c.Value);
                        ilg.Stelem(typeof(long));
                    }
                    ilg.Ldloc(longArray);
                    ilg.Ldstr(mapping.TypeDesc.FullName);
                    MethodInfo XmlSerializationWriter_FromEnum = typeof(XmlSerializationWriter).GetMethod(
                        "FromEnum",
                        CodeGenerator.StaticBindingFlags,
                        null,
                        new Type[] { typeof(Int64), typeof(String[]), typeof(Int64[]), typeof(String) },
                        null
                        );
                    ilg.Call(XmlSerializationWriter_FromEnum);
                    ilg.Stloc(sLoc);
                    ilg.Br(endSwitchLabel);
                }
                else {
                    ilg.Br(defaultLabel);
                    // Case bodies
                    for (int i = 0; i < caseLabels.Count; i++) {
                        ilg.MarkLabel(caseLabels[i]);
                        ilg.Ldc(retValues[i]);
                        ilg.Stloc(sLoc);
                        ilg.Br(endSwitchLabel);
                    }
                    MethodInfo CultureInfo_get_InvariantCulture = typeof(CultureInfo).GetMethod(
                        "get_InvariantCulture",
                        CodeGenerator.StaticBindingFlags,
                        null,
                        CodeGenerator.EmptyTypeArray,
                        null
                        );
                    MethodInfo Int64_ToString = typeof(Int64).GetMethod(
                        "ToString",
                        CodeGenerator.InstanceBindingFlags,
                        null,
                        new Type[] { typeof(IFormatProvider) },
                        null
                        );
                    MethodInfo XmlSerializationWriter_CreateInvalidEnumValueException = typeof(XmlSerializationWriter).GetMethod(
                        "CreateInvalidEnumValueException",
                        CodeGenerator.InstanceBindingFlags,
                        null,
                        new Type[] { typeof(object), typeof(string) },
                        null
                        );
                    // Default body
                    ilg.MarkLabel(defaultLabel);
                    ilg.Ldarg(0);
                    ilg.Ldarg("v");
                    ilg.ConvertValue(mapping.TypeDesc.Type, typeof(Int64));
                    LocalBuilder numLoc = ilg.DeclareLocal(typeof(Int64), "num");
                    ilg.Stloc(numLoc);
                    // Invoke method on Value type need address
                    ilg.LdlocAddress(numLoc);
                    ilg.Call(CultureInfo_get_InvariantCulture);
                    ilg.Call(Int64_ToString);
                    ilg.Ldstr(mapping.TypeDesc.FullName);
                    ilg.Call(XmlSerializationWriter_CreateInvalidEnumValueException);
                    ilg.Throw();
                }
                ilg.MarkLabel(endSwitchLabel);
            }
            ilg.Ldloc(sLoc);
            ilg.EndMethod();
        }
 
        void WriteDerivedTypes(StructMapping mapping) {
            for (StructMapping derived = mapping.DerivedMappings; derived != null; derived = derived.NextDerivedMapping) {
                ilg.InitElseIf();
                WriteTypeCompare("t", derived.TypeDesc.Type);
                ilg.AndIf();
 
                string methodName = ReferenceMapping(derived);
 
#if DEBUG
                // use exception in the place of Debug.Assert to avoid throwing asserts from a server process such as aspnet_ewp.exe
                if (methodName == null) throw new InvalidOperationException("deriaved from " + mapping.TypeDesc.FullName + ", " + Res.GetString(Res.XmlInternalErrorMethod, derived.TypeDesc.Name) + Environment.StackTrace);
#endif
 
                List<Type> argTypes = new List<Type>();
                ilg.Ldarg(0);
                argTypes.Add(typeof(string));
                ilg.Ldarg("n");
                argTypes.Add(typeof(string));
                ilg.Ldarg("ns");
                object oVar = ilg.GetVariable("o");
                Type oType = ilg.GetVariableType(oVar);
                ilg.Load(oVar);
                ilg.ConvertValue(oType, derived.TypeDesc.Type);
                argTypes.Add(derived.TypeDesc.Type);
                if (derived.TypeDesc.IsNullable) {
                    argTypes.Add(typeof(Boolean));
                    ilg.Ldarg("isNullable");
                }
                argTypes.Add(typeof(Boolean));
                ilg.Ldc(true);
                MethodInfo methodBuilder = EnsureMethodBuilder(typeBuilder,
                    methodName,
                    CodeGenerator.PrivateMethodAttributes,
                    typeof(void),
                    argTypes.ToArray());
                ilg.Call(methodBuilder);
                ilg.GotoMethodEnd();
 
                WriteDerivedTypes(derived);
            }
        }
 
        void WriteEnumAndArrayTypes() {
            foreach (TypeScope scope in Scopes) {
                foreach (Mapping m in scope.TypeMappings) {
                    if (m is EnumMapping) {
                        EnumMapping mapping = (EnumMapping)m;
                        ilg.InitElseIf();
                        WriteTypeCompare("t", mapping.TypeDesc.Type);
                        // WriteXXXTypeCompare leave bool on the stack
                        ilg.AndIf();
 
                        string methodName = ReferenceMapping(mapping);
 
#if DEBUG
                        // use exception in the place of Debug.Assert to avoid throwing asserts from a server process such as aspnet_ewp.exe
                        if (methodName == null) throw new InvalidOperationException(Res.GetString(Res.XmlInternalErrorMethod, mapping.TypeDesc.Name) + Environment.StackTrace);
#endif
                        MethodInfo XmlSerializationWriter_get_Writer = typeof(XmlSerializationWriter).GetMethod(
                            "get_Writer",
                            CodeGenerator.InstanceBindingFlags,
                            null,
                            CodeGenerator.EmptyTypeArray,
                            null
                            );
                        MethodInfo XmlWriter_WriteStartElement = typeof(XmlWriter).GetMethod(
                            "WriteStartElement",
                            CodeGenerator.InstanceBindingFlags,
                            null,
                            new Type[] { typeof(String), typeof(String) },
                            null
                            );
                        ilg.Ldarg(0);
                        ilg.Call(XmlSerializationWriter_get_Writer);
                        ilg.Ldarg("n");
                        ilg.Ldarg("ns");
                        ilg.Call(XmlWriter_WriteStartElement);
                        MethodInfo XmlSerializationWriter_WriteXsiType = typeof(XmlSerializationWriter).GetMethod(
                            "WriteXsiType",
                            CodeGenerator.InstanceBindingFlags,
                            null,
                            new Type[] { typeof(String), typeof(String) },
                            null
                            );
                        ilg.Ldarg(0);
                        ilg.Ldstr(mapping.TypeName);
                        ilg.Ldstr(mapping.Namespace);
                        ilg.Call(XmlSerializationWriter_WriteXsiType);
                        MethodBuilder methodBuilder = EnsureMethodBuilder(typeBuilder,
                            methodName,
                            CodeGenerator.PrivateMethodAttributes,
                            typeof(string),
                            new Type[] { mapping.TypeDesc.Type }
                        );
                        MethodInfo XmlWriter_WriteString = typeof(XmlWriter).GetMethod(
                            "WriteString",
                            CodeGenerator.InstanceBindingFlags,
                            null,
                            new Type[] { typeof(String) },
                            null
                            );
                        ilg.Ldarg(0);
                        ilg.Call(XmlSerializationWriter_get_Writer);
                        object oVar = ilg.GetVariable("o");
                        ilg.Ldarg(0);
                        ilg.Load(oVar);
                        ilg.ConvertValue(ilg.GetVariableType(oVar), mapping.TypeDesc.Type);
                        ilg.Call(methodBuilder);
                        ilg.Call(XmlWriter_WriteString);
                        MethodInfo XmlWriter_WriteEndElement = typeof(XmlWriter).GetMethod(
                            "WriteEndElement",
                            CodeGenerator.InstanceBindingFlags,
                            null,
                            CodeGenerator.EmptyTypeArray,
                            null
                            );
                        ilg.Ldarg(0);
                        ilg.Call(XmlSerializationWriter_get_Writer);
                        ilg.Call(XmlWriter_WriteEndElement);
                        ilg.GotoMethodEnd();
                    }
                    else if (m is ArrayMapping) {
                        ArrayMapping mapping = m as ArrayMapping;
                        if (mapping == null) continue;
                        ilg.InitElseIf();
                        if (mapping.TypeDesc.IsArray)
                            WriteArrayTypeCompare("t", mapping.TypeDesc.Type);
                        else
                            WriteTypeCompare("t", mapping.TypeDesc.Type);
                        // WriteXXXTypeCompare leave bool on the stack
                        ilg.AndIf();
                        ilg.EnterScope();
 
                        MethodInfo XmlSerializationWriter_get_Writer = typeof(XmlSerializationWriter).GetMethod(
                            "get_Writer",
                            CodeGenerator.InstanceBindingFlags,
                            null,
                            CodeGenerator.EmptyTypeArray,
                            null
                            );
                        MethodInfo XmlWriter_WriteStartElement = typeof(XmlWriter).GetMethod(
                            "WriteStartElement",
                            CodeGenerator.InstanceBindingFlags,
                            null,
                            new Type[] { typeof(String), typeof(String) },
                            null
                            );
                        ilg.Ldarg(0);
                        ilg.Call(XmlSerializationWriter_get_Writer);
                        ilg.Ldarg("n");
                        ilg.Ldarg("ns");
                        ilg.Call(XmlWriter_WriteStartElement);
                        MethodInfo XmlSerializationWriter_WriteXsiType = typeof(XmlSerializationWriter).GetMethod(
                            "WriteXsiType",
                            CodeGenerator.InstanceBindingFlags,
                            null,
                            new Type[] { typeof(String), typeof(String) },
                            null
                            );
                        ilg.Ldarg(0);
                        ilg.Ldstr(mapping.TypeName);
                        ilg.Ldstr(mapping.Namespace);
                        ilg.Call(XmlSerializationWriter_WriteXsiType);
 
                        WriteMember(new SourceInfo("o", "o", null, null, ilg), null, mapping.ElementsSortedByDerivation, null, null, mapping.TypeDesc, true);
 
                        MethodInfo XmlWriter_WriteEndElement = typeof(XmlWriter).GetMethod(
                            "WriteEndElement",
                            CodeGenerator.InstanceBindingFlags,
                            null,
                            CodeGenerator.EmptyTypeArray,
                            null
                            );
                        ilg.Ldarg(0);
                        ilg.Call(XmlSerializationWriter_get_Writer);
                        ilg.Call(XmlWriter_WriteEndElement);
                        ilg.GotoMethodEnd();
                        ilg.ExitScope();
                    }
                }
            }
        }
 
        void WriteStructMethod(StructMapping mapping) {
            string methodName = (string)MethodNames[mapping];
 
            ilg = new CodeGenerator(this.typeBuilder);
            List<Type> argTypes = new List<Type>(5);
            List<string> argNames = new List<string>(5);
            argTypes.Add(typeof(string));
            argNames.Add("n");
            argTypes.Add(typeof(string));
            argNames.Add("ns");
            argTypes.Add(mapping.TypeDesc.Type);
            argNames.Add("o");
            if (mapping.TypeDesc.IsNullable) {
                argTypes.Add(typeof(Boolean));
                argNames.Add("isNullable");
            }
            argTypes.Add(typeof(Boolean));
            argNames.Add("needType");
            ilg.BeginMethod(typeof(void),
                GetMethodBuilder(methodName),
                argTypes.ToArray(),
                argNames.ToArray(),
                CodeGenerator.PrivateMethodAttributes);
            if (mapping.TypeDesc.IsNullable) {
                ilg.If(ilg.GetArg("o"), Cmp.EqualTo, null);
                {
                    ilg.If(ilg.GetArg("isNullable"), Cmp.EqualTo, true);
                    {
                        MethodInfo XmlSerializationWriter_WriteNullTagLiteral = typeof(XmlSerializationWriter).GetMethod(
                                "WriteNullTagLiteral",
                                CodeGenerator.InstanceBindingFlags,
                                null,
                                new Type[] { typeof(String), typeof(String) },
                                null
                                );
                        ilg.Ldarg(0);
                        ilg.Ldarg("n");
                        ilg.Ldarg("ns");
                        ilg.Call(XmlSerializationWriter_WriteNullTagLiteral);
                    }
                    ilg.EndIf();
                    ilg.GotoMethodEnd();
                }
                ilg.EndIf();
            }
            ilg.If(ilg.GetArg("needType"), Cmp.NotEqualTo, true); // if (!needType)
 
            LocalBuilder tLoc = ilg.DeclareLocal(typeof(Type), "t");
            MethodInfo Object_GetType = typeof(object).GetMethod(
                    "GetType",
                    CodeGenerator.InstanceBindingFlags,
                    null,
                    CodeGenerator.EmptyTypeArray,
                    null
                    );
            ArgBuilder oArg = ilg.GetArg("o");
            ilg.LdargAddress(oArg);
            ilg.ConvertAddress(oArg.ArgType, typeof(object));
            ilg.Call(Object_GetType);
            ilg.Stloc(tLoc);
            WriteTypeCompare("t", mapping.TypeDesc.Type);
            // Bool on the stack from WriteTypeCompare.
            ilg.If(); // if (t == typeof(...))
            WriteDerivedTypes(mapping);
            if (mapping.TypeDesc.IsRoot)
                WriteEnumAndArrayTypes();
            ilg.Else();
            if (mapping.TypeDesc.IsRoot) {
                MethodInfo XmlSerializationWriter_WriteTypedPrimitive = typeof(XmlSerializationWriter).GetMethod(
                        "WriteTypedPrimitive",
                        CodeGenerator.InstanceBindingFlags,
                        null,
                        new Type[] { typeof(String), typeof(String), typeof(Object), typeof(Boolean) },
                        null
                        );
                ilg.Ldarg(0);
                ilg.Ldarg("n");
                ilg.Ldarg("ns");
                ilg.Ldarg("o");
                ilg.Ldc(true);
                ilg.Call(XmlSerializationWriter_WriteTypedPrimitive);
                ilg.GotoMethodEnd();
            }
            else {
                MethodInfo XmlSerializationWriter_CreateUnknownTypeException = typeof(XmlSerializationWriter).GetMethod(
                    "CreateUnknownTypeException",
                    CodeGenerator.InstanceBindingFlags,
                    null,
                    new Type[] { typeof(Object) },
                    null
                    );
                ilg.Ldarg(0);
                ilg.Ldarg(oArg);
                ilg.ConvertValue(oArg.ArgType, typeof(Object));
                ilg.Call(XmlSerializationWriter_CreateUnknownTypeException);
                ilg.Throw();
            }
            ilg.EndIf(); // if (t == typeof(...))
            ilg.EndIf(); // if (!needType)
 
            if (!mapping.TypeDesc.IsAbstract) {
                if (mapping.TypeDesc.Type != null && typeof(XmlSchemaObject).IsAssignableFrom(mapping.TypeDesc.Type)) {
                    MethodInfo XmlSerializationWriter_set_EscapeName = typeof(XmlSerializationWriter).GetMethod(
                        "set_EscapeName",
                        CodeGenerator.InstanceBindingFlags,
                        null,
                        new Type[] { typeof(Boolean) },
                        null
                        );
                    ilg.Ldarg(0);
                    ilg.Ldc(false);
                    ilg.Call(XmlSerializationWriter_set_EscapeName);
                }
 
                string xmlnsSource = null;
                MemberMapping[] members = TypeScope.GetAllMembers(mapping, memberInfos);
                int xmlnsMember = FindXmlnsIndex(members);
                if (xmlnsMember >= 0) {
                    MemberMapping member = members[xmlnsMember];
                    CodeIdentifier.CheckValidIdentifier(member.Name);
                    xmlnsSource = RaCodeGen.GetStringForMember("o", member.Name, mapping.TypeDesc);
                }
 
                ilg.Ldarg(0);
                ilg.Ldarg("n");
                ilg.Ldarg("ns");
                ArgBuilder argO = ilg.GetArg("o");
                ilg.Ldarg(argO);
                ilg.ConvertValue(argO.ArgType, typeof(Object));
                ilg.Ldc(false);
                if (xmlnsSource == null)
                    ilg.Load(null);
                else {
                    System.Diagnostics.Debug.Assert(xmlnsSource.StartsWith("o.@", StringComparison.Ordinal));
                    ILGenLoad(xmlnsSource);
                }
 
                MethodInfo XmlSerializationWriter_WriteStartElement = typeof(XmlSerializationWriter).GetMethod(
                        "WriteStartElement",
                        CodeGenerator.InstanceBindingFlags,
                        null,
                        new Type[] { typeof(String), typeof(String), typeof(Object), typeof(Boolean), typeof(XmlSerializerNamespaces) },
                        null
                        );
                ilg.Call(XmlSerializationWriter_WriteStartElement);
                if (!mapping.TypeDesc.IsRoot) {
                    ilg.If(ilg.GetArg("needType"), Cmp.EqualTo, true);
                    {
                        MethodInfo XmlSerializationWriter_WriteXsiType = typeof(XmlSerializationWriter).GetMethod(
                                "WriteXsiType",
                                CodeGenerator.InstanceBindingFlags,
                                null,
                                new Type[] { typeof(String), typeof(String) },
                                null
                                );
                        ilg.Ldarg(0);
                        ilg.Ldstr(mapping.TypeName);
                        ilg.Ldstr(mapping.Namespace);
                        ilg.Call(XmlSerializationWriter_WriteXsiType);
                    }
                    ilg.EndIf();
                }
                for (int i = 0; i < members.Length; i++) {
                    MemberMapping m = members[i];
                    if (m.Attribute != null) {
                        CodeIdentifier.CheckValidIdentifier(m.Name);
                        if (m.CheckShouldPersist) {
                            ilg.LdargAddress(oArg);
                            ilg.Call(m.CheckShouldPersistMethodInfo);
                            ilg.If();
                        }
                        if (m.CheckSpecified != SpecifiedAccessor.None) {
                            string memberGet = RaCodeGen.GetStringForMember("o", m.Name + "Specified", mapping.TypeDesc);
                            ILGenLoad(memberGet);
                            ilg.If();
                        }
                        WriteMember(RaCodeGen.GetSourceForMember("o", m, mapping.TypeDesc, ilg), m.Attribute, m.TypeDesc, "o");
 
                        if (m.CheckSpecified != SpecifiedAccessor.None) {
                            ilg.EndIf();
                        }
                        if (m.CheckShouldPersist) {
                            ilg.EndIf();
                        }
                    }
                }
 
                for (int i = 0; i < members.Length; i++) {
                    MemberMapping m = members[i];
                    if (m.Xmlns != null)
                        continue;
                    CodeIdentifier.CheckValidIdentifier(m.Name);
                    bool checkShouldPersist = m.CheckShouldPersist && (m.Elements.Length > 0 || m.Text != null);
 
                    if (checkShouldPersist) {
                        ilg.LdargAddress(oArg);
                        ilg.Call(m.CheckShouldPersistMethodInfo);
                        ilg.If();
                    }
                    if (m.CheckSpecified != SpecifiedAccessor.None) {
                        string memberGet = RaCodeGen.GetStringForMember("o", m.Name + "Specified", mapping.TypeDesc);
                        ILGenLoad(memberGet);
                        ilg.If();
                    }
 
                    string choiceSource = null;
                    if (m.ChoiceIdentifier != null) {
                        CodeIdentifier.CheckValidIdentifier(m.ChoiceIdentifier.MemberName);
                        choiceSource = RaCodeGen.GetStringForMember("o", m.ChoiceIdentifier.MemberName, mapping.TypeDesc);
                    }
 
                    WriteMember(RaCodeGen.GetSourceForMember("o", m, m.MemberInfo, mapping.TypeDesc, ilg), choiceSource, m.ElementsSortedByDerivation, m.Text, m.ChoiceIdentifier, m.TypeDesc, true);
 
 
                    if (m.CheckSpecified != SpecifiedAccessor.None) {
                        ilg.EndIf();
                    }
                    if (checkShouldPersist) {
                        ilg.EndIf();
                    }
                }
                WriteEndElement("o");
            }
            ilg.EndMethod();
        }
 
        bool CanOptimizeWriteListSequence(TypeDesc listElementTypeDesc) {
 
            // check to see if we can write values of the attribute sequentially
            // currently we have only one data type (XmlQualifiedName) that we can not write "inline", 
            // because we need to output xmlns:qx="..." for each of the qnames
 
            return (listElementTypeDesc != null && listElementTypeDesc != QnameTypeDesc);
        }
 
        void WriteMember(SourceInfo source, AttributeAccessor attribute, TypeDesc memberTypeDesc, string parent) {
            if (memberTypeDesc.IsAbstract) return;
            if (memberTypeDesc.IsArrayLike) {
                string aVar = "a" + memberTypeDesc.Name;
                string aiVar = "ai" + memberTypeDesc.Name;
                string iVar = "i";
                string fullTypeName = memberTypeDesc.CSharpName;
                WriteArrayLocalDecl(fullTypeName, aVar, source, memberTypeDesc);
                if (memberTypeDesc.IsNullable) {
                    ilg.Ldloc(memberTypeDesc.Type, aVar);
                    ilg.Load(null);
                    ilg.If(Cmp.NotEqualTo);
                }
                if (attribute.IsList) {
                    if (CanOptimizeWriteListSequence(memberTypeDesc.ArrayElementTypeDesc)) {
                        string ns = attribute.Form == XmlSchemaForm.Qualified ? attribute.Namespace : String.Empty;
                        MethodInfo XmlSerializationWriter_get_Writer = typeof(XmlSerializationWriter).GetMethod(
                            "get_Writer",
                            CodeGenerator.InstanceBindingFlags,
                            null,
                            CodeGenerator.EmptyTypeArray,
                            null
                            );
                        MethodInfo XmlWriter_WriteStartAttribute = typeof(XmlWriter).GetMethod(
                            "WriteStartAttribute",
                            CodeGenerator.InstanceBindingFlags,
                            null,
                            new Type[] { typeof(String), typeof(String), typeof(String) },
                            null
                            );
                        ilg.Ldarg(0);
                        ilg.Call(XmlSerializationWriter_get_Writer);
                        ilg.Load(null);
                        ilg.Ldstr(attribute.Name);
                        ilg.Ldstr(ns);
                        ilg.Call(XmlWriter_WriteStartAttribute);
                    }
                    else {
                        LocalBuilder sbLoc = ilg.DeclareOrGetLocal(typeof(StringBuilder), "sb");
                        ConstructorInfo StringBuilder_ctor = typeof(StringBuilder).GetConstructor(
                            CodeGenerator.InstanceBindingFlags,
                            null,
                            CodeGenerator.EmptyTypeArray,
                            null
                            );
                        ilg.New(StringBuilder_ctor);
                        ilg.Stloc(sbLoc);
                    }
                }
                TypeDesc arrayElementTypeDesc = memberTypeDesc.ArrayElementTypeDesc;
 
                if (memberTypeDesc.IsEnumerable) {
                    throw CodeGenerator.NotSupported("CDF15337, DDB176069: Also fail in whidbey IEnumerable member with XmlAttributeAttribute");
                }
                else {
                    if (memberTypeDesc.IsArray) {
                        LocalBuilder localI = ilg.DeclareOrGetLocal(typeof(Int32), iVar);
                        ilg.For(localI, 0, ilg.GetLocal(aVar));
                    }
                    else {
                        LocalBuilder localI = ilg.DeclareOrGetLocal(typeof(Int32), iVar);
                        ilg.For(localI, 0, ilg.GetLocal(aVar));
                    }
                    WriteLocalDecl(aiVar, RaCodeGen.GetStringForArrayMember(aVar, iVar, memberTypeDesc), arrayElementTypeDesc.Type);
                }
                if (attribute.IsList) {
                    string methodName;
                    Type methodType;
                    Type argType = typeof(string);
                    // check to see if we can write values of the attribute sequentially
                    if (CanOptimizeWriteListSequence(memberTypeDesc.ArrayElementTypeDesc)) {
                        ilg.Ldloc(iVar);
                        ilg.Ldc(0);
                        ilg.If(Cmp.NotEqualTo);
                        MethodInfo XmlSerializationWriter_get_Writer = typeof(XmlSerializationWriter).GetMethod(
                            "get_Writer",
                            CodeGenerator.InstanceBindingFlags,
                            null,
                            CodeGenerator.EmptyTypeArray,
                            null
                            );
                        MethodInfo XmlWriter_WriteString = typeof(XmlWriter).GetMethod(
                            "WriteString",
                            CodeGenerator.InstanceBindingFlags,
                            null,
                            new Type[] { typeof(String) },
                            null
                            );
                        ilg.Ldarg(0);
                        ilg.Call(XmlSerializationWriter_get_Writer);
                        ilg.Ldstr(" ");
                        ilg.Call(XmlWriter_WriteString);
                        ilg.EndIf();
                        ilg.Ldarg(0);
                        methodName = "WriteValue";
                        methodType = typeof(XmlSerializationWriter);
                    }
                    else {
                        MethodInfo StringBuilder_Append = typeof(StringBuilder).GetMethod(
                            "Append",
                            CodeGenerator.InstanceBindingFlags,
                            null,
                            new Type[] { typeof(string) },
                            null
                            );
                        ilg.Ldloc(iVar);
                        ilg.Ldc(0);
                        ilg.If(Cmp.NotEqualTo);
                        ilg.Ldloc("sb");
                        ilg.Ldstr(" ");
                        ilg.Call(StringBuilder_Append);
                        ilg.Pop();
                        ilg.EndIf();
                        ilg.Ldloc("sb");
                        methodName = "Append";
                        methodType = typeof(StringBuilder);
                    }
                    if (attribute.Mapping is EnumMapping)
                        WriteEnumValue((EnumMapping)attribute.Mapping, new SourceInfo(aiVar, aiVar, null, arrayElementTypeDesc.Type, ilg), out argType);
                    else
                        WritePrimitiveValue(arrayElementTypeDesc, new SourceInfo(aiVar, aiVar, null, arrayElementTypeDesc.Type, ilg), out argType);
                    MethodInfo method = methodType.GetMethod(
                        methodName,
                        CodeGenerator.InstanceBindingFlags,
                        null,
                        new Type[] { argType },
                        null
                        );
                    ilg.Call(method);
                    if (method.ReturnType != typeof(void))
                        ilg.Pop();
                }
                else {
                    WriteAttribute(new SourceInfo(aiVar, aiVar, null, null, ilg), attribute, parent);
                }
                if (memberTypeDesc.IsEnumerable)
                    throw CodeGenerator.NotSupported("CDF15337, DDB176069: Also fail in whidbey IEnumerable member with XmlAttributeAttribute");
                else
                    ilg.EndFor();
                if (attribute.IsList) {
                    // check to see if we can write values of the attribute sequentially
                    if (CanOptimizeWriteListSequence(memberTypeDesc.ArrayElementTypeDesc)) {
                        MethodInfo XmlSerializationWriter_get_Writer = typeof(XmlSerializationWriter).GetMethod(
                            "get_Writer",
                            CodeGenerator.InstanceBindingFlags,
                            null,
                            CodeGenerator.EmptyTypeArray,
                            null
                            );
                        MethodInfo XmlWriter_WriteEndAttribute = typeof(XmlWriter).GetMethod(
                            "WriteEndAttribute",
                            CodeGenerator.InstanceBindingFlags,
                            null,
                            CodeGenerator.EmptyTypeArray,
                            null
                            );
                        ilg.Ldarg(0);
                        ilg.Call(XmlSerializationWriter_get_Writer);
                        ilg.Call(XmlWriter_WriteEndAttribute);
                    }
                    else {
                        MethodInfo StringBuilder_get_Length = typeof(StringBuilder).GetMethod(
                            "get_Length",
                            CodeGenerator.InstanceBindingFlags,
                            null,
                            CodeGenerator.EmptyTypeArray,
                            null
                            );
                        ilg.Ldloc("sb");
                        ilg.Call(StringBuilder_get_Length);
                        ilg.Ldc(0);
                        ilg.If(Cmp.NotEqualTo);
 
                        List<Type> argTypes = new List<Type>();
                        ilg.Ldarg(0);
                        ilg.Ldstr(attribute.Name);
                        argTypes.Add(typeof(string));
                        string ns = attribute.Form == XmlSchemaForm.Qualified ? attribute.Namespace : String.Empty;
                        if (ns != null) {
                            ilg.Ldstr(ns);
                            argTypes.Add(typeof(string));
                        }
                        MethodInfo Object_ToString = typeof(Object).GetMethod(
                            "ToString",
                            CodeGenerator.InstanceBindingFlags,
                            null,
                            CodeGenerator.EmptyTypeArray,
                            null
                            );
                        ilg.Ldloc("sb");
                        ilg.Call(Object_ToString);
                        argTypes.Add(typeof(string));
                        MethodInfo XmlSerializationWriter_WriteAttribute = typeof(XmlSerializationWriter).GetMethod(
                             "WriteAttribute",
                             CodeGenerator.InstanceBindingFlags,
                             null,
                             argTypes.ToArray(),
                             null
                             );
                        ilg.Call(XmlSerializationWriter_WriteAttribute);
                        ilg.EndIf();
                    }
                }
 
                if (memberTypeDesc.IsNullable) {
                    ilg.EndIf();
                }
            }
            else {
                WriteAttribute(source, attribute, parent);
            }
        }
 
        void WriteAttribute(SourceInfo source, AttributeAccessor attribute, string parent) {
            if (attribute.Mapping is SpecialMapping) {
                SpecialMapping special = (SpecialMapping)attribute.Mapping;
                if (special.TypeDesc.Kind == TypeKind.Attribute || special.TypeDesc.CanBeAttributeValue) {
                    System.Diagnostics.Debug.Assert(parent == "o" || parent == "p");
                    MethodInfo XmlSerializationWriter_WriteXmlAttribute = typeof(XmlSerializationWriter).GetMethod(
                        "WriteXmlAttribute",
                        CodeGenerator.InstanceBindingFlags,
                        null,
                        new Type[] { typeof(XmlNode), typeof(Object) },
                        null
                        );
                    ilg.Ldarg(0);
                    ilg.Ldloc(source.Source);
                    ilg.Ldarg(parent);
                    ilg.ConvertValue(ilg.GetArg(parent).ArgType, typeof(Object));
                    ilg.Call(XmlSerializationWriter_WriteXmlAttribute);
                }
                else
                    throw new InvalidOperationException(Res.GetString(Res.XmlInternalError));
            }
            else {
                TypeDesc typeDesc = attribute.Mapping.TypeDesc;
                source = source.CastTo(typeDesc);
                WritePrimitive("WriteAttribute", attribute.Name, attribute.Form == XmlSchemaForm.Qualified ? attribute.Namespace : "", GetConvertedDefaultValue(source.Type, attribute.Default), source, attribute.Mapping, false, false, false);
            }
        }
 
        static object GetConvertedDefaultValue(Type targetType, object rawDefaultValue) {
            if (targetType == null) {
                return rawDefaultValue;
            }
 
            object convertedDefaultValue;
            if (!targetType.TryConvertTo(rawDefaultValue, out convertedDefaultValue)) {
                return rawDefaultValue;
            }
 
            return convertedDefaultValue;
        }
 
        void WriteMember(SourceInfo source, string choiceSource, ElementAccessor[] elements, TextAccessor text, ChoiceIdentifierAccessor choice, TypeDesc memberTypeDesc, bool writeAccessors) {
            if (memberTypeDesc.IsArrayLike &&
                !(elements.Length == 1 && elements[0].Mapping is ArrayMapping))
                WriteArray(source, choiceSource, elements, text, choice, memberTypeDesc);
            else
                // NOTE: Use different variable name to work around reuse same variable name in different scope
                WriteElements(source, choiceSource, elements, text, choice, "a" + memberTypeDesc.Name, writeAccessors, memberTypeDesc.IsNullable);
        }
 
 
        void WriteArray(SourceInfo source, string choiceSource, ElementAccessor[] elements, TextAccessor text, ChoiceIdentifierAccessor choice, TypeDesc arrayTypeDesc) {
            if (elements.Length == 0 && text == null) return;
            string arrayTypeName = arrayTypeDesc.CSharpName;
            string aName = "a" + arrayTypeDesc.Name;
            WriteArrayLocalDecl(arrayTypeName, aName, source, arrayTypeDesc);
            LocalBuilder aLoc = ilg.GetLocal(aName);
            if (arrayTypeDesc.IsNullable) {
                ilg.Ldloc(aLoc);
                ilg.Load(null);
                ilg.If(Cmp.NotEqualTo);
            }
 
            string cName = null;
            if (choice != null) {
                string choiceFullName = choice.Mapping.TypeDesc.CSharpName;
                SourceInfo choiceSourceInfo = new SourceInfo(choiceSource, null, choice.MemberInfo, null, ilg);
                cName = "c" + choice.Mapping.TypeDesc.Name;
                WriteArrayLocalDecl(choiceFullName + "[]", cName, choiceSourceInfo, choice.Mapping.TypeDesc);
                // write check for the choice identifier array
                Label labelEnd = ilg.DefineLabel();
                Label labelTrue = ilg.DefineLabel();
                LocalBuilder cLoc = ilg.GetLocal(cName);
                ilg.Ldloc(cLoc);
                ilg.Load(null);
                ilg.Beq(labelTrue);
                ilg.Ldloc(cLoc);
                ilg.Ldlen();
                ilg.Ldloc(aLoc);
                ilg.Ldlen();
                ilg.Clt();
                ilg.Br(labelEnd);
                ilg.MarkLabel(labelTrue);
                ilg.Ldc(true);
                ilg.MarkLabel(labelEnd);
                ilg.If();
                MethodInfo XmlSerializationWriter_CreateInvalidChoiceIdentifierValueException = typeof(XmlSerializationWriter).GetMethod(
                    "CreateInvalidChoiceIdentifierValueException",
                    CodeGenerator.InstanceBindingFlags,
                    null,
                    new Type[] { typeof(String), typeof(String) },
                    null
                    );
                ilg.Ldarg(0);
                ilg.Ldstr(choice.Mapping.TypeDesc.FullName);
                ilg.Ldstr(choice.MemberName);
                ilg.Call(XmlSerializationWriter_CreateInvalidChoiceIdentifierValueException);
                ilg.Throw();
                ilg.EndIf();
            }
 
            WriteArrayItems(elements, text, choice, arrayTypeDesc, aName, cName);
            if (arrayTypeDesc.IsNullable) {
                ilg.EndIf();
            }
        }
 
        void WriteArrayItems(ElementAccessor[] elements, TextAccessor text, ChoiceIdentifierAccessor choice, TypeDesc arrayTypeDesc, string arrayName, string choiceName)
        {
            TypeDesc arrayElementTypeDesc = arrayTypeDesc.ArrayElementTypeDesc;
 
            // The logic here is that
            // 1) Try to get the public "GetEnumerator" method. If the method exists, then use this method.
            // 2) If there's no public method exist, check if the type implemented IEnumerable<T>. If so, call the explicit method
            // 3) Otherwise, call the IEnumerable.GetEnumerator method
            if (arrayTypeDesc.IsEnumerable)
            {
                LocalBuilder eLoc = ilg.DeclareLocal(typeof(IEnumerator), "e");
                MethodInfo getEnumeratorMethod = arrayTypeDesc.Type.GetMethod(
                    "GetEnumerator",
                    CodeGenerator.InstancePublicBindingFlags,
                    null,
                    CodeGenerator.EmptyTypeArray,
                    null);
 
 
                if (getEnumeratorMethod != null && typeof(IEnumerator).IsAssignableFrom(getEnumeratorMethod.ReturnType))
                {
                    ilg.LoadAddress(ilg.GetVariable(arrayName));
                }
                else
                {
                    ilg.Load(ilg.GetVariable(arrayName));
                    Type typeIEnumerable = arrayTypeDesc.IsGenericInterface ? typeof(IEnumerable<>).MakeGenericType(arrayElementTypeDesc.Type) : typeof(IEnumerable);
 
                    getEnumeratorMethod = typeIEnumerable.GetMethod(
                        "GetEnumerator",
                        CodeGenerator.InstanceBindingFlags,
                        null,
                        CodeGenerator.EmptyTypeArray,
                        null);
 
                    ilg.ConvertValue(arrayTypeDesc.Type, typeIEnumerable);
                }
 
                ilg.Call(getEnumeratorMethod);
                ilg.ConvertValue(getEnumeratorMethod.ReturnType, typeof(IEnumerator));
                ilg.Stloc(eLoc);
 
                ilg.Ldloc(eLoc);
                ilg.Load(null);
                ilg.If(Cmp.NotEqualTo);
                ilg.WhileBegin();
                string arrayNamePlusA = (arrayName).Replace(arrayTypeDesc.Name, "") + "a" + arrayElementTypeDesc.Name;
                string arrayNamePlusI = (arrayName).Replace(arrayTypeDesc.Name, "") + "i" + arrayElementTypeDesc.Name;
                WriteLocalDecl(arrayNamePlusI, "e.Current", arrayElementTypeDesc.Type);
                WriteElements(new SourceInfo(arrayNamePlusI, null, null, arrayElementTypeDesc.Type, ilg), choiceName + "i", elements, text, choice, arrayNamePlusA, true, true);
 
                ilg.WhileBeginCondition(); // while (e.MoveNext())
                MethodInfo IEnumerator_MoveNext = typeof(IEnumerator).GetMethod(
                    "MoveNext",
                    CodeGenerator.InstanceBindingFlags,
                    null,
                    CodeGenerator.EmptyTypeArray,
                    null
                    );
                ilg.Ldloc(eLoc);
                ilg.Call(IEnumerator_MoveNext);
                ilg.WhileEndCondition();
                ilg.WhileEnd();
 
                ilg.EndIf(); // if (e != null)
            }
            else {
                // Filter out type specific for index (code match reusing local).
                string iPlusArrayName = "i" + (arrayName).Replace(arrayTypeDesc.Name, "");
                string arrayNamePlusA = (arrayName).Replace(arrayTypeDesc.Name, "") + "a" + arrayElementTypeDesc.Name;
                string arrayNamePlusI = (arrayName).Replace(arrayTypeDesc.Name, "") + "i" + arrayElementTypeDesc.Name;
                LocalBuilder localI = ilg.DeclareOrGetLocal(typeof(Int32), iPlusArrayName);
                ilg.For(localI, 0, ilg.GetLocal(arrayName));
                int count = elements.Length + (text == null ? 0 : 1);
                if (count > 1) {
                    WriteLocalDecl(arrayNamePlusI, RaCodeGen.GetStringForArrayMember(arrayName, iPlusArrayName, arrayTypeDesc), arrayElementTypeDesc.Type);
                    if (choice != null) {
                        WriteLocalDecl(choiceName + "i", RaCodeGen.GetStringForArrayMember(choiceName, iPlusArrayName, choice.Mapping.TypeDesc), choice.Mapping.TypeDesc.Type);
                    }
                    WriteElements(new SourceInfo(arrayNamePlusI, null, null, arrayElementTypeDesc.Type, ilg), choiceName + "i", elements, text, choice, arrayNamePlusA, true, arrayElementTypeDesc.IsNullable);
                }
                else {
                    WriteElements(new SourceInfo(RaCodeGen.GetStringForArrayMember(arrayName, iPlusArrayName, arrayTypeDesc), null, null, arrayElementTypeDesc.Type, ilg), null, elements, text, choice, arrayNamePlusA, true, arrayElementTypeDesc.IsNullable);
                }
                ilg.EndFor();
            }
        }
 
        void WriteElements(SourceInfo source, string enumSource, ElementAccessor[] elements, TextAccessor text, ChoiceIdentifierAccessor choice, string arrayName, bool writeAccessors, bool isNullable) {
            if (elements.Length == 0 && text == null) return;
            if (elements.Length == 1 && text == null) {
                TypeDesc td = elements[0].IsUnbounded ? elements[0].Mapping.TypeDesc.CreateArrayTypeDesc() : elements[0].Mapping.TypeDesc;
                if (!elements[0].Any && !elements[0].Mapping.TypeDesc.IsOptionalValue)
                    source = source.CastTo(td);
                WriteElement(source, elements[0], arrayName, writeAccessors);
            }
            else {
                bool doEndIf = false;
                if (isNullable && choice == null) {
                    source.Load(typeof(object));
                    ilg.Load(null);
                    ilg.If(Cmp.NotEqualTo);
                    doEndIf = true;
                }
                int anyCount = 0;
                ArrayList namedAnys = new ArrayList();
                ElementAccessor unnamedAny = null; // can only have one
                bool wroteFirstIf = false;
                string enumTypeName = choice == null ? null : choice.Mapping.TypeDesc.FullName;
 
                for (int i = 0; i < elements.Length; i++) {
                    ElementAccessor element = elements[i];
 
                    if (element.Any) {
                        anyCount++;
                        if (element.Name != null && element.Name.Length > 0)
                            namedAnys.Add(element);
                        else if (unnamedAny == null)
                            unnamedAny = element;
                    }
                    else if (choice != null) {
                        string fullTypeName = element.Mapping.TypeDesc.CSharpName;
                        object enumValue;
                        string enumFullName = enumTypeName + ".@" + FindChoiceEnumValue(element, (EnumMapping)choice.Mapping, out enumValue);
 
                        if (wroteFirstIf) ilg.InitElseIf();
                        else { wroteFirstIf = true; ilg.InitIf(); }
                        ILGenLoad(enumSource, choice == null ? null : choice.Mapping.TypeDesc.Type);
                        ilg.Load(enumValue);
                        ilg.Ceq();
                        if (isNullable && !element.IsNullable) {
                            Label labelFalse = ilg.DefineLabel();
                            Label labelEnd = ilg.DefineLabel();
                            ilg.Brfalse(labelFalse);
                            source.Load(typeof(object));
                            ilg.Load(null);
                            ilg.Cne();
                            ilg.Br_S(labelEnd);
                            ilg.MarkLabel(labelFalse);
                            ilg.Ldc(false);
                            ilg.MarkLabel(labelEnd);
                        }
                        ilg.AndIf();
 
                        WriteChoiceTypeCheck(source, fullTypeName, choice, enumFullName, element.Mapping.TypeDesc);
 
                        SourceInfo castedSource = source;
                        castedSource = source.CastTo(element.Mapping.TypeDesc);
                        WriteElement(element.Any ? source : castedSource, element, arrayName, writeAccessors);
                    }
                    else {
                        TypeDesc td = element.IsUnbounded ? element.Mapping.TypeDesc.CreateArrayTypeDesc() : element.Mapping.TypeDesc;
                        string fullTypeName = td.CSharpName;
                        if (wroteFirstIf) ilg.InitElseIf();
                        else { wroteFirstIf = true; ilg.InitIf(); }
                        WriteInstanceOf(source, td.Type);
                        // WriteInstanceOf leave bool on the stack
                        ilg.AndIf();
                        SourceInfo castedSource = source;
                        castedSource = source.CastTo(td);
                        WriteElement(element.Any ? source : castedSource, element, arrayName, writeAccessors);
                    }
                }
                if (wroteFirstIf) {
                    if (anyCount > 0) {
                        // See "else " below
                        if (elements.Length - anyCount > 0) { // NOOP
                        }
                        else ilg.EndIf();
                    }
                }
                if (anyCount > 0) {
                    if (elements.Length - anyCount > 0) ilg.InitElseIf();
                    else ilg.InitIf();
 
                    string fullTypeName = typeof(XmlElement).FullName;
 
                    source.Load(typeof(object));
                    ilg.IsInst(typeof(XmlElement));
                    ilg.Load(null);
                    ilg.Cne();
                    ilg.AndIf();
 
                    LocalBuilder elemLoc = ilg.DeclareLocal(typeof(XmlElement), "elem");
                    source.Load(typeof(XmlElement));
                    ilg.Stloc(elemLoc);
 
                    int c = 0;
 
                    foreach (ElementAccessor element in namedAnys) {
                        if (c++ > 0) ilg.InitElseIf();
                        else ilg.InitIf();
 
                        string enumFullName = null;
 
                        Label labelEnd, labelFalse;
                        if (choice != null) {
                            object enumValue;
                            enumFullName = enumTypeName + ".@" + FindChoiceEnumValue(element, (EnumMapping)choice.Mapping, out enumValue);
                            labelFalse = ilg.DefineLabel();
                            labelEnd = ilg.DefineLabel();
                            ILGenLoad(enumSource, choice == null ? null : choice.Mapping.TypeDesc.Type);
                            ilg.Load(enumValue);
                            ilg.Bne(labelFalse);
                            if (isNullable && !element.IsNullable) {
                                source.Load(typeof(object));
                                ilg.Load(null);
                                ilg.Cne();
                            }
                            else {
                                ilg.Ldc(true);
                            }
                            ilg.Br(labelEnd);
                            ilg.MarkLabel(labelFalse);
                            ilg.Ldc(false);
                            ilg.MarkLabel(labelEnd);
                            ilg.AndIf();
                        }
                        labelFalse = ilg.DefineLabel();
                        labelEnd = ilg.DefineLabel();
                        MethodInfo XmlNode_get_Name = typeof(XmlNode).GetMethod(
                            "get_Name",
                            CodeGenerator.InstanceBindingFlags,
                            null,
                            CodeGenerator.EmptyTypeArray,
                            null
                            );
                        MethodInfo XmlNode_get_NamespaceURI = typeof(XmlNode).GetMethod(
                            "get_NamespaceURI",
                            CodeGenerator.InstanceBindingFlags,
                            null,
                            CodeGenerator.EmptyTypeArray,
                            null
                            );
                        ilg.Ldloc(elemLoc);
                        ilg.Call(XmlNode_get_Name);
                        ilg.Ldstr(element.Name);
                        MethodInfo String_op_Equality = typeof(string).GetMethod(
                            "op_Equality",
                            CodeGenerator.StaticBindingFlags,
                            null,
                            new Type[] { typeof(string), typeof(string) },
                            null
                            );
                        ilg.Call(String_op_Equality);
                        ilg.Brfalse(labelFalse);
                        ilg.Ldloc(elemLoc);
                        ilg.Call(XmlNode_get_NamespaceURI);
                        ilg.Ldstr(element.Namespace);
                        ilg.Call(String_op_Equality);
                        ilg.Br(labelEnd);
                        ilg.MarkLabel(labelFalse);
                        ilg.Ldc(false);
                        ilg.MarkLabel(labelEnd);
                        if (choice != null) ilg.If();
                        else ilg.AndIf();
                        WriteElement(new SourceInfo("elem", null, null, elemLoc.LocalType, ilg), element, arrayName, writeAccessors);
 
                        if (choice != null) {
                            ilg.Else();
 
                            MethodInfo XmlSerializationWriter_CreateChoiceIdentifierValueException = typeof(XmlSerializationWriter).GetMethod(
                                "CreateChoiceIdentifierValueException",
                                CodeGenerator.InstanceBindingFlags,
                                null,
                                new Type[] { typeof(String), typeof(String), typeof(String), typeof(String) },
                                null
                                );
                            ilg.Ldarg(0);
                            ilg.Ldstr(enumFullName);
                            ilg.Ldstr(choice.MemberName);
                            ilg.Ldloc(elemLoc);
                            ilg.Call(XmlNode_get_Name);
                            ilg.Ldloc(elemLoc);
                            ilg.Call(XmlNode_get_NamespaceURI);
                            ilg.Call(XmlSerializationWriter_CreateChoiceIdentifierValueException);
                            ilg.Throw();
                            ilg.EndIf();
                        }
                    }
                    if (c > 0) {
                        ilg.Else();
                    }
                    if (unnamedAny != null) {
                        WriteElement(new SourceInfo("elem", null, null, elemLoc.LocalType, ilg), unnamedAny, arrayName, writeAccessors);
                    }
                    else {
                        MethodInfo XmlSerializationWriter_CreateUnknownAnyElementException = typeof(XmlSerializationWriter).GetMethod(
                            "CreateUnknownAnyElementException",
                            CodeGenerator.InstanceBindingFlags,
                            null,
                            new Type[] { typeof(String), typeof(String) },
                            null
                            );
                        ilg.Ldarg(0);
                        ilg.Ldloc(elemLoc);
                        MethodInfo XmlNode_get_Name = typeof(XmlNode).GetMethod(
                            "get_Name",
                            CodeGenerator.InstanceBindingFlags,
                            null,
                            CodeGenerator.EmptyTypeArray,
                            null
                            );
                        MethodInfo XmlNode_get_NamespaceURI = typeof(XmlNode).GetMethod(
                            "get_NamespaceURI",
                            CodeGenerator.InstanceBindingFlags,
                            null,
                            CodeGenerator.EmptyTypeArray,
                            null
                            );
                        ilg.Call(XmlNode_get_Name);
                        ilg.Ldloc(elemLoc);
                        ilg.Call(XmlNode_get_NamespaceURI);
                        ilg.Call(XmlSerializationWriter_CreateUnknownAnyElementException);
                        ilg.Throw();
                    }
                    if (c > 0) {
                        ilg.EndIf();
                    }
                }
                if (text != null) {
                    string fullTypeName = text.Mapping.TypeDesc.CSharpName;
                    if (elements.Length > 0) {
                        ilg.InitElseIf();
                        WriteInstanceOf(source, text.Mapping.TypeDesc.Type);
                        ilg.AndIf();
                        SourceInfo castedSource = source.CastTo(text.Mapping.TypeDesc);
                        WriteText(castedSource, text);
                    }
                    else {
                        SourceInfo castedSource = source.CastTo(text.Mapping.TypeDesc);
                        WriteText(castedSource, text);
                    }
                }
                if (elements.Length > 0) {
 
                    if (isNullable) {
                        ilg.InitElseIf();
                        source.Load(null);
                        ilg.Load(null);
                        ilg.AndIf(Cmp.NotEqualTo);
                    }
                    else {
                        ilg.Else();
                    }
 
                    MethodInfo XmlSerializationWriter_CreateUnknownTypeException = typeof(XmlSerializationWriter).GetMethod(
                        "CreateUnknownTypeException",
                        CodeGenerator.InstanceBindingFlags,
                        null,
                        new Type[] { typeof(Object) },
                        null
                        );
                    ilg.Ldarg(0);
                    source.Load(typeof(object));
                    ilg.Call(XmlSerializationWriter_CreateUnknownTypeException);
                    ilg.Throw();
 
                    ilg.EndIf();
                }
                // See ilg.If() cond above
                if (doEndIf) // if (isNullable && choice == null)
                    ilg.EndIf();
            }
        }
 
        void WriteText(SourceInfo source, TextAccessor text) {
            if (text.Mapping is PrimitiveMapping) {
                PrimitiveMapping mapping = (PrimitiveMapping)text.Mapping;
                Type argType;
                ilg.Ldarg(0);
                if (text.Mapping is EnumMapping) {
                    WriteEnumValue((EnumMapping)text.Mapping, source, out argType);
                }
                else {
                    WritePrimitiveValue(mapping.TypeDesc, source, out argType);
                }
                MethodInfo XmlSerializationWriter_WriteValue = typeof(XmlSerializationWriter).GetMethod(
                    "WriteValue",
                    CodeGenerator.InstanceBindingFlags,
                    null,
                    new Type[] { argType },
                    null
                    );
                ilg.Call(XmlSerializationWriter_WriteValue);
            }
            else if (text.Mapping is SpecialMapping) {
                SpecialMapping mapping = (SpecialMapping)text.Mapping;
                switch (mapping.TypeDesc.Kind) {
                    case TypeKind.Node:
                        MethodInfo WriteTo = source.Type.GetMethod(
                            "WriteTo",
                            CodeGenerator.InstanceBindingFlags,
                            null,
                            new Type[] { typeof(XmlWriter) },
                            null
                            );
                        MethodInfo XmlSerializationWriter_get_Writer = typeof(XmlSerializationWriter).GetMethod(
                            "get_Writer",
                            CodeGenerator.InstanceBindingFlags,
                            null,
                            CodeGenerator.EmptyTypeArray,
                            null
                            );
                        source.Load(source.Type);
                        ilg.Ldarg(0);
                        ilg.Call(XmlSerializationWriter_get_Writer);
                        ilg.Call(WriteTo);
                        break;
                    default:
                        throw new InvalidOperationException(Res.GetString(Res.XmlInternalError));
                }
            }
        }
 
        void WriteElement(SourceInfo source, ElementAccessor element, string arrayName, bool writeAccessor) {
            string name = writeAccessor ? element.Name : element.Mapping.TypeName;
            string ns = element.Any && element.Name.Length == 0 ? null : (element.Form == XmlSchemaForm.Qualified ? (writeAccessor ? element.Namespace : element.Mapping.Namespace) : "");
            if (element.Mapping is NullableMapping) {
                if (source.Type == element.Mapping.TypeDesc.Type) {
                    MethodInfo Nullable_get_HasValue = element.Mapping.TypeDesc.Type.GetMethod(
                        "get_HasValue",
                        CodeGenerator.InstanceBindingFlags,
                        null,
                        CodeGenerator.EmptyTypeArray,
                        null
                        );
                    source.LoadAddress(element.Mapping.TypeDesc.Type);
                    ilg.Call(Nullable_get_HasValue);
                }
                else {
                    source.Load(null);
                    ilg.Load(null);
                    ilg.Cne();
                }
                ilg.If();
                string fullTypeName = element.Mapping.TypeDesc.BaseTypeDesc.CSharpName;
                SourceInfo castedSource = source.CastTo(element.Mapping.TypeDesc.BaseTypeDesc);
                ElementAccessor e = element.Clone();
                e.Mapping = ((NullableMapping)element.Mapping).BaseMapping;
                WriteElement(e.Any ? source : castedSource, e, arrayName, writeAccessor);
                if (element.IsNullable) {
                    ilg.Else();
                    WriteLiteralNullTag(element.Name, element.Form == XmlSchemaForm.Qualified ? element.Namespace : "");
                }
                ilg.EndIf();
            }
            else if (element.Mapping is ArrayMapping) {
                ArrayMapping mapping = (ArrayMapping)element.Mapping;
                if (element.IsUnbounded) {
                    throw CodeGenerator.NotSupported("Unreachable: IsUnbounded is never set true!");
                }
                else {
                    ilg.EnterScope();
                    string fullTypeName = mapping.TypeDesc.CSharpName;
                    WriteArrayLocalDecl(fullTypeName, arrayName, source, mapping.TypeDesc);
                    if (element.IsNullable) {
                        WriteNullCheckBegin(arrayName, element);
                    }
                    else {
                        if (mapping.TypeDesc.IsNullable) {
                            ilg.Ldloc(ilg.GetLocal(arrayName));
                            ilg.Load(null);
                            ilg.If(Cmp.NotEqualTo);
                        }
                    }
                    WriteStartElement(name, ns, false);
                    WriteArrayItems(mapping.ElementsSortedByDerivation, null, null, mapping.TypeDesc, arrayName, null);
                    WriteEndElement();
                    if (element.IsNullable) {
                        ilg.EndIf();
                    }
                    else {
                        if (mapping.TypeDesc.IsNullable) {
                            ilg.EndIf();
                        }
                    }
                    ilg.ExitScope();
                }
            }
            else if (element.Mapping is EnumMapping) {
                WritePrimitive("WriteElementString", name, ns, element.Default, source, element.Mapping, false, true, element.IsNullable);
            }
            else if (element.Mapping is PrimitiveMapping) {
                PrimitiveMapping mapping = (PrimitiveMapping)element.Mapping;
                if (mapping.TypeDesc == QnameTypeDesc)
                    WriteQualifiedNameElement(name, ns, GetConvertedDefaultValue(source.Type,  element.Default), source, element.IsNullable, mapping);
                else {
                    string suffixRaw = mapping.TypeDesc.XmlEncodingNotRequired ? "Raw" : "";
                    WritePrimitive(element.IsNullable ? ("WriteNullableStringLiteral" + suffixRaw) : ("WriteElementString" + suffixRaw),
                                   name, ns, GetConvertedDefaultValue(source.Type, element.Default), source, mapping, false, true, element.IsNullable);
                }
            }
            else if (element.Mapping is StructMapping) {
                StructMapping mapping = (StructMapping)element.Mapping;
 
                string methodName = ReferenceMapping(mapping);
 
#if DEBUG
                // use exception in the place of Debug.Assert to avoid throwing asserts from a server process such as aspnet_ewp.exe
                if (methodName == null) throw new InvalidOperationException(Res.GetString(Res.XmlInternalErrorMethod, mapping.TypeDesc.Name) + Environment.StackTrace);
#endif
                List<Type> argTypes = new List<Type>();
                ilg.Ldarg(0);
                ilg.Ldstr(name);
                argTypes.Add(typeof(string));
                ilg.Ldstr(ns);
                argTypes.Add(typeof(string));
                source.Load(mapping.TypeDesc.Type);
                argTypes.Add(mapping.TypeDesc.Type);
                if (mapping.TypeDesc.IsNullable) {
                    ilg.Ldc(element.IsNullable);
                    argTypes.Add(typeof(Boolean));
                }
                ilg.Ldc(false);
                argTypes.Add(typeof(Boolean));
                MethodBuilder methodBuilder = EnsureMethodBuilder(typeBuilder,
                    methodName,
                    CodeGenerator.PrivateMethodAttributes,
                    typeof(void),
                    argTypes.ToArray());
                ilg.Call(methodBuilder);
            }
            else if (element.Mapping is SpecialMapping) {
                SpecialMapping mapping = (SpecialMapping)element.Mapping;
                TypeDesc td = mapping.TypeDesc;
                string fullTypeName = td.CSharpName;
 
 
                if (element.Mapping is SerializableMapping) {
                    WriteElementCall("WriteSerializable", typeof(IXmlSerializable), source, name, ns, element.IsNullable, !element.Any);
                }
                else {
                    // XmlNode, XmlElement
                    Label ifLabel1 = ilg.DefineLabel();
                    Label ifLabel2 = ilg.DefineLabel();
                    source.Load(null);
                    ilg.IsInst(typeof(XmlNode));
                    ilg.Brtrue(ifLabel1);
                    source.Load(null);
                    ilg.Load(null);
                    ilg.Ceq();
                    ilg.Br(ifLabel2);
                    ilg.MarkLabel(ifLabel1);
                    ilg.Ldc(true);
                    ilg.MarkLabel(ifLabel2);
                    ilg.If();
 
                    WriteElementCall("WriteElementLiteral", typeof(XmlNode), source, name, ns, element.IsNullable, element.Any);
 
                    ilg.Else();
 
                    MethodInfo XmlSerializationWriter_CreateInvalidAnyTypeException = typeof(XmlSerializationWriter).GetMethod(
                        "CreateInvalidAnyTypeException",
                        CodeGenerator.InstanceBindingFlags,
                        null,
                        new Type[] { typeof(Object) },
                        null
                        );
                    ilg.Ldarg(0);
                    source.Load(null);
                    ilg.Call(XmlSerializationWriter_CreateInvalidAnyTypeException);
                    ilg.Throw();
 
                    ilg.EndIf();
                }
            }
            else {
                throw new InvalidOperationException(Res.GetString(Res.XmlInternalError));
            }
        }
 
        void WriteElementCall(string func, Type cast, SourceInfo source, string name, string ns, bool isNullable, bool isAny) {
            MethodInfo XmlSerializationWriter_func = typeof(XmlSerializationWriter).GetMethod(
                 func,
                 CodeGenerator.InstanceBindingFlags,
                 null,
                 new Type[] { cast, typeof(String), typeof(String), typeof(Boolean), typeof(Boolean) },
                 null
                 );
            ilg.Ldarg(0);
            source.Load(cast);
            ilg.Ldstr(name);
            ilg.Ldstr(ns);
            ilg.Ldc(isNullable);
            ilg.Ldc(isAny);
            ilg.Call(XmlSerializationWriter_func);
        }
 
        void WriteCheckDefault(SourceInfo source, object value, bool isNullable) {
 
            if (value is string && ((string)value).Length == 0) {
                // special case for string compare
                Label labelEnd = ilg.DefineLabel();
                Label labelFalse = ilg.DefineLabel();
                Label labelTrue = ilg.DefineLabel();
                source.Load(typeof(string));
                if (isNullable)
                    // check == null with false
                    ilg.Brfalse(labelTrue);
                else
                    //check != null with false
                    ilg.Brfalse(labelFalse);
                MethodInfo String_get_Length = typeof(string).GetMethod(
                    "get_Length",
                    CodeGenerator.InstanceBindingFlags,
                    null,
                    CodeGenerator.EmptyTypeArray,
                    null
                    );
                source.Load(typeof(string));
                ilg.Call(String_get_Length);
                ilg.Ldc(0);
                ilg.Cne();
                ilg.Br(labelEnd);
                if (isNullable) {
                    ilg.MarkLabel(labelTrue);
                    ilg.Ldc(true);
                }
                else {
                    ilg.MarkLabel(labelFalse);
                    ilg.Ldc(false);
                }
                ilg.MarkLabel(labelEnd);
                ilg.If();
            }
            else {
                if (value == null) {
                    source.Load(typeof(object));
                    ilg.Load(null);
                    ilg.Cne();
                }
                else if (value.GetType().IsPrimitive) {
                    source.Load(null);
                    ilg.Ldc(Convert.ChangeType(value, source.Type, CultureInfo.InvariantCulture));
                    ilg.Cne();
                }
                else {
                    Type valueType = value.GetType();
                    source.Load(valueType);
                    ilg.Ldc(value);
                    MethodInfo op_Inequality = valueType.GetMethod(
                                "op_Inequality",
                                CodeGenerator.StaticBindingFlags,
                                null,
                                new Type[] { valueType, valueType },
                                null
                                );
                    if (op_Inequality != null)
                        ilg.Call(op_Inequality);
                    else
                        ilg.Cne();
                }
                ilg.If();
            }
        }
 
        void WriteChoiceTypeCheck(SourceInfo source, string fullTypeName, ChoiceIdentifierAccessor choice, string enumName, TypeDesc typeDesc) {
 
            Label labelFalse = ilg.DefineLabel();
            Label labelEnd = ilg.DefineLabel();
            source.Load(typeof(object));
            ilg.Load(null);
            ilg.Beq(labelFalse);
            WriteInstanceOf(source, typeDesc.Type);
            // Negative
            ilg.Ldc(false);
            ilg.Ceq();
            ilg.Br(labelEnd);
            ilg.MarkLabel(labelFalse);
            ilg.Ldc(false);
            ilg.MarkLabel(labelEnd);
            ilg.If();
            MethodInfo XmlSerializationWriter_CreateMismatchChoiceException = typeof(XmlSerializationWriter).GetMethod(
                "CreateMismatchChoiceException",
                CodeGenerator.InstanceBindingFlags,
                null,
                new Type[] { typeof(String), typeof(String), typeof(String) },
                null
                );
            ilg.Ldarg(0);
            ilg.Ldstr(typeDesc.FullName);
            ilg.Ldstr(choice.MemberName);
            ilg.Ldstr(enumName);
            ilg.Call(XmlSerializationWriter_CreateMismatchChoiceException);
            ilg.Throw();
            ilg.EndIf();
        }
 
        void WriteNullCheckBegin(string source, ElementAccessor element) {
            LocalBuilder local = ilg.GetLocal(source);
            Debug.Assert(!local.LocalType.IsValueType);
            ilg.Load(local);
            ilg.Load(null);
            ilg.If(Cmp.EqualTo);
            WriteLiteralNullTag(element.Name, element.Form == XmlSchemaForm.Qualified ? element.Namespace : "");
            ilg.Else();
        }
 
 
        void WriteNamespaces(string source) {
            MethodInfo XmlSerializationWriter_WriteNamespaceDeclarations = typeof(XmlSerializationWriter).GetMethod(
                "WriteNamespaceDeclarations",
                CodeGenerator.InstanceBindingFlags,
                null,
                new Type[] { typeof(XmlSerializerNamespaces) },
                null
                );
            ilg.Ldarg(0);
            ILGenLoad(source, typeof(XmlSerializerNamespaces));
            ilg.Call(XmlSerializationWriter_WriteNamespaceDeclarations);
        }
 
        int FindXmlnsIndex(MemberMapping[] members) {
            for (int i = 0; i < members.Length; i++) {
                if (members[i].Xmlns == null)
                    continue;
                return i;
            }
            return -1;
        }
 
 
        void WriteLocalDecl(string variableName, string initValue, Type type) {
            RaCodeGen.WriteLocalDecl(variableName, new SourceInfo(initValue, initValue, null, type, ilg));
        }
 
        void WriteArrayLocalDecl(string typeName, string variableName, SourceInfo initValue, TypeDesc arrayTypeDesc) {
            RaCodeGen.WriteArrayLocalDecl(typeName, variableName, initValue, arrayTypeDesc);
        }
        void WriteTypeCompare(string variable, Type type) {
            RaCodeGen.WriteTypeCompare(variable, type, ilg);
        }
        void WriteInstanceOf(SourceInfo source, Type type) {
            RaCodeGen.WriteInstanceOf(source, type, ilg);
        }
        void WriteArrayTypeCompare(string variable, Type arrayType) {
            RaCodeGen.WriteArrayTypeCompare(variable, arrayType, ilg);
        }
 
 
        string FindChoiceEnumValue(ElementAccessor element, EnumMapping choiceMapping, out object eValue) {
            string enumValue = null;
            eValue = null;
 
            for (int i = 0; i < choiceMapping.Constants.Length; i++) {
                string xmlName = choiceMapping.Constants[i].XmlName;
 
                if (element.Any && element.Name.Length == 0) {
                    if (xmlName == "##any:") {
                        enumValue = choiceMapping.Constants[i].Name;
                        eValue = Enum.ToObject(choiceMapping.TypeDesc.Type, choiceMapping.Constants[i].Value);
                        break;
                    }
                    continue;
                }
                int colon = xmlName.LastIndexOf(':');
                string choiceNs = colon < 0 ? choiceMapping.Namespace : xmlName.Substring(0, colon);
                string choiceName = colon < 0 ? xmlName : xmlName.Substring(colon + 1);
 
                if (element.Name == choiceName) {
                    if ((element.Form == XmlSchemaForm.Unqualified && string.IsNullOrEmpty(choiceNs)) || element.Namespace == choiceNs) {
                        enumValue = choiceMapping.Constants[i].Name;
                        eValue = Enum.ToObject(choiceMapping.TypeDesc.Type, choiceMapping.Constants[i].Value);
                        break;
                    }
                }
            }
            if (enumValue == null || enumValue.Length == 0) {
                if (element.Any && element.Name.Length == 0) {
                    // Type {0} is missing enumeration value '##any' for XmlAnyElementAttribute.
                    throw new InvalidOperationException(Res.GetString(Res.XmlChoiceMissingAnyValue, choiceMapping.TypeDesc.FullName));
                }
                // Type {0} is missing value for '{1}'.
                throw new InvalidOperationException(Res.GetString(Res.XmlChoiceMissingValue, choiceMapping.TypeDesc.FullName, element.Namespace + ":" + element.Name, element.Name, element.Namespace));
            }
            CodeIdentifier.CheckValidIdentifier(enumValue);
            return enumValue;
        }
    }
 
    internal class ReflectionAwareILGen {
        private const string hexDigits = "0123456789ABCDEF";
        const string arrayMemberKey = "0";
        // reflectionVariables holds mapping between a reflection entity
        // referenced in the generated code (such as TypeInfo,
        // FieldInfo) and the variable which represent the entity (and
        // initialized before).
        // The types of reflection entity and corresponding key is
        // given below.
        // ----------------------------------------------------------------------------------
        // Entity           Key
        // ----------------------------------------------------------------------------------
        // Assembly         assembly.FullName
        // Type             CodeIdentifier.EscapedKeywords(type.FullName)
        // Field            fieldName+":"+CodeIdentifier.EscapedKeywords(containingType.FullName>)
        // Property         propertyName+":"+CodeIdentifier.EscapedKeywords(containingType.FullName)
        // ArrayAccessor    "0:"+CodeIdentifier.EscapedKeywords(typeof(Array).FullName)
        // MyCollectionAccessor     "0:"+CodeIdentifier.EscapedKeywords(typeof(MyCollection).FullName)
        // ----------------------------------------------------------------------------------
        internal ReflectionAwareILGen() { }
 
        internal void WriteReflectionInit(TypeScope scope) {
            foreach (Type type in scope.Types) {
                TypeDesc typeDesc = scope.GetTypeDesc(type);
            }
        }
 
        internal void ILGenForEnumLongValue(CodeGenerator ilg, string variable) {
            ArgBuilder argV = ilg.GetArg(variable);
            ilg.Ldarg(argV);
            ilg.ConvertValue(argV.ArgType, typeof(long));
        }
 
        internal string GetStringForTypeof(string typeFullName) {
            {
                return "typeof(" + typeFullName + ")";
            }
        }
        internal string GetStringForMember(string obj, string memberName, TypeDesc typeDesc) {
            return obj + ".@" + memberName;
 
        }
        internal SourceInfo GetSourceForMember(string obj, MemberMapping member, TypeDesc typeDesc, CodeGenerator ilg)
        {
            return GetSourceForMember(obj, member, member.MemberInfo, typeDesc, ilg);
        }
        internal SourceInfo GetSourceForMember(string obj, MemberMapping member, MemberInfo memberInfo, TypeDesc typeDesc, CodeGenerator ilg)
        {
            return new SourceInfo(GetStringForMember(obj, member.Name, typeDesc), obj, memberInfo, member.TypeDesc.Type, ilg);
        }
        /*
        Exception GetReflectionVariableException(string typeFullName, string memberName){
            string key;
            if(memberName == null)
                key = typeFullName;
            else
                key = memberName+":"+typeFullName;
            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            foreach(object varAvail in reflectionVariables.Keys){
                sb.Append(varAvail.ToString());
                sb.Append("\n");
            }
            return new Exception("No reflection variable for " + key + "\nAvailable keys\n"+sb.ToString());
        }*/
 
        internal void ILGenForEnumMember(CodeGenerator ilg, Type type, string memberName) {
            ilg.Ldc(Enum.Parse(type, memberName, false));
        }
        internal string GetStringForArrayMember(string arrayName, string subscript, TypeDesc arrayTypeDesc) {
            {
                return arrayName + "[" + subscript + "]";
            }
 
        }
        internal string GetStringForMethod(string obj, string typeFullName, string memberName) {
            return obj + "." + memberName + "(";
 
        }
        internal void ILGenForCreateInstance(CodeGenerator ilg, Type type, bool ctorInaccessible, bool cast) {
            if (!ctorInaccessible) {
                ConstructorInfo ctor = type.GetConstructor(
                       CodeGenerator.InstanceBindingFlags,
                       null,
                       CodeGenerator.EmptyTypeArray,
                       null
                       );
                if (ctor != null)
                    ilg.New(ctor);
                else {
                    Debug.Assert(type.IsValueType);
                    LocalBuilder tmpLoc = ilg.GetTempLocal(type);
                    ilg.Ldloca(tmpLoc);
                    ilg.InitObj(type);
                    ilg.Ldloc(tmpLoc);
                }
                return;
            }
            ILGenForCreateInstance(ilg, type, cast ? type : null, ctorInaccessible);
        }
 
        internal void ILGenForCreateInstance(CodeGenerator ilg, Type type, Type cast, bool nonPublic) {
            // Special case DBNull
            if (type == typeof(DBNull)) {
                FieldInfo DBNull_Value = typeof(DBNull).GetField("Value", CodeGenerator.StaticBindingFlags);
                ilg.LoadMember(DBNull_Value);
                return;
            }
 
            // Special case XElement
            // codegen the same as 'internal XElement : this("default") { }'
            if (type.FullName == "System.Xml.Linq.XElement") {
                Type xName = type.Assembly.GetType("System.Xml.Linq.XName");
                if (xName != null) {
                    MethodInfo XName_op_Implicit = xName.GetMethod(
                        "op_Implicit",
                        CodeGenerator.StaticBindingFlags,
                        null,
                        new Type[] { typeof(String) },
                        null
                        );
                    ConstructorInfo XElement_ctor = type.GetConstructor(
                        CodeGenerator.InstanceBindingFlags,
                        null,
                        new Type[] { xName },
                        null
                        );
                    if (XName_op_Implicit != null && XElement_ctor != null) {
                        ilg.Ldstr("default");
                        ilg.Call(XName_op_Implicit);
                        ilg.New(XElement_ctor);
                        return;
                    }
                }
            }
 
            BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.CreateInstance;
            if (nonPublic) {
                bindingFlags |= BindingFlags.NonPublic;
            }
 
            MethodInfo Activator_CreateInstance = typeof(Activator).GetMethod(
                  "CreateInstance",
                  CodeGenerator.StaticBindingFlags,
                  null,
                  new Type[] { typeof(Type), typeof(BindingFlags), typeof(Binder), typeof(Object[]), typeof(CultureInfo) },
                  null
                  );
            ilg.Ldc(type);
            ilg.Load((int)bindingFlags);
            ilg.Load(null);
            ilg.NewArray(typeof(Object), 0);
            ilg.Load(null);
            ilg.Call(Activator_CreateInstance);
            if (cast != null)
                ilg.ConvertValue(Activator_CreateInstance.ReturnType, cast);
        }
 
        internal void WriteLocalDecl(string variableName, SourceInfo initValue) {
            Type localType = initValue.Type;
            LocalBuilder localA = initValue.ILG.DeclareOrGetLocal(localType, variableName);
            if (initValue.Source != null) {
                if (initValue == "null") {
                    initValue.ILG.Load(null);
                }
                else {
                    if (initValue.Arg.StartsWith("o.@", StringComparison.Ordinal)) {
                        Debug.Assert(initValue.MemberInfo != null);
                        Debug.Assert(initValue.MemberInfo.Name == initValue.Arg.Substring(3));
                        initValue.ILG.LoadMember(initValue.ILG.GetLocal("o"), initValue.MemberInfo);
                    }
                    else if (initValue.Source.EndsWith("]", StringComparison.Ordinal)) {
                        initValue.Load(initValue.Type);
                    }
                    else if (initValue.Source == "fixup.Source" || initValue.Source == "e.Current") {
                        String[] vars = initValue.Source.Split('.');
                        object fixup = initValue.ILG.GetVariable(vars[0]);
                        PropertyInfo propInfo = initValue.ILG.GetVariableType(fixup).GetProperty(vars[1]);
                        initValue.ILG.LoadMember(fixup, propInfo);
                        initValue.ILG.ConvertValue(propInfo.PropertyType, localA.LocalType);
                    }
                    else {
                        object sVar = initValue.ILG.GetVariable(initValue.Arg);
                        initValue.ILG.Load(sVar);
                        initValue.ILG.ConvertValue(initValue.ILG.GetVariableType(sVar), localA.LocalType);
                    }
                }
                initValue.ILG.Stloc(localA);
            }
        }
 
        internal void WriteCreateInstance(string source, bool ctorInaccessible, Type type, CodeGenerator ilg) {
            LocalBuilder sLoc = ilg.DeclareOrGetLocal(type, source);
            ILGenForCreateInstance(ilg, type, ctorInaccessible, ctorInaccessible);
            ilg.Stloc(sLoc);
        }
        internal void WriteInstanceOf(SourceInfo source, Type type, CodeGenerator ilg) {
            {
                source.Load(typeof(object));
                ilg.IsInst(type);
                ilg.Load(null);
                ilg.Cne();
                return;
            }
 
        }
 
        internal void WriteArrayLocalDecl(string typeName, string variableName, SourceInfo initValue, TypeDesc arrayTypeDesc) {
            Debug.Assert(typeName == arrayTypeDesc.CSharpName || typeName == arrayTypeDesc.CSharpName + "[]");
            Type localType = (typeName == arrayTypeDesc.CSharpName) ? arrayTypeDesc.Type : arrayTypeDesc.Type.MakeArrayType();
            // This may need reused varialble to get code compat?
            LocalBuilder local = initValue.ILG.DeclareOrGetLocal(localType, variableName);
            if (initValue != null) {
                initValue.Load(local.LocalType);
                initValue.ILG.Stloc(local);
            }
        }
        internal void WriteTypeCompare(string variable, Type type, CodeGenerator ilg) {
            Debug.Assert(type != null);
            Debug.Assert(ilg != null);
            ilg.Ldloc(typeof(Type), variable);
            ilg.Ldc(type);
            ilg.Ceq();
        }
        internal void WriteArrayTypeCompare(string variable, Type arrayType, CodeGenerator ilg) {
            {
                Debug.Assert(arrayType != null);
                Debug.Assert(ilg != null);
                ilg.Ldloc(typeof(Type), variable);
                ilg.Ldc(arrayType);
                ilg.Ceq();
                return;
            }
        }
 
        internal static string GetQuotedCSharpString(IndentedWriter notUsed, string value) {
            if (value == null) {
                return null;
            }
            StringBuilder writer = new StringBuilder();
            writer.Append("@\"");
            writer.Append(GetCSharpString(value));
            writer.Append("\"");
            return writer.ToString();
        }
        internal static string GetCSharpString(string value) {
            if (value == null) {
                return null;
            }
            StringBuilder writer = new StringBuilder();
            foreach (char ch in value) {
                if (ch < 32) {
                    if (ch == '\r')
                        writer.Append("\\r");
                    else if (ch == '\n')
                        writer.Append("\\n");
                    else if (ch == '\t')
                        writer.Append("\\t");
                    else {
                        byte b = (byte)ch;
                        writer.Append("\\x");
                        writer.Append(hexDigits[b >> 4]);
                        writer.Append(hexDigits[b & 0xF]);
                    }
                }
                else if (ch == '\"') {
                    writer.Append("\"\"");
                }
                else {
                    writer.Append(ch);
                }
            }
            return writer.ToString();
        }
 
    }
 
}