File: Microsoft\Build\Tasks\Xaml\ClassGenerator.cs
Project: ndp\cdf\src\NetFx40\XamlBuildTask\XamlBuildTask.csproj (XamlBuildTask)
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//------------------------------------------------------------
 
namespace Microsoft.Build.Tasks.Xaml
{
    using System;
    using System.CodeDom;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.IO;
    using System.Linq;
    using System.Xml.Linq;
    using System.Reflection;
    using System.Xaml;
    using System.Xaml.Schema;
    using System.Windows.Markup;
    using System.Runtime;
    using System.Globalization;
    using System.Diagnostics.CodeAnalysis;
    using System.CodeDom.Compiler;
    using System.Runtime.InteropServices;
    using System.Xml;
    using Microsoft.Build.Utilities;
    using XamlBuildTask;
 
    class ClassGenerator
    {
        static CodeThisReferenceExpression CodeThis = new CodeThisReferenceExpression();
        static CodeAttributeDeclaration generatedCodeAttribute;
 
        TaskLoggingHelper buildLogger;
        CodeDomProvider codeDomProvider;
        string language;
 
 
        public ClassGenerator(TaskLoggingHelper buildLogger, CodeDomProvider codeDomProvider, string language)
        {
            this.buildLogger = buildLogger;
            this.codeDomProvider = codeDomProvider;
            this.language = language;
        }
 
        public CodeCompileUnit Generate(ClassData classData)
        {
            if (classData == null)
            {
                throw FxTrace.Exception.ArgumentNull("classData");
            }
            CodeCompileUnit result = new CodeCompileUnit();
 
            // Add global namespace
            CodeNamespace globalNamespace = new CodeNamespace();
            result.Namespaces.Add(globalNamespace);
 
            CodeTypeDeclaration classDeclaration = GenerateClass(classData);
            if (!String.IsNullOrEmpty(classData.Namespace))
            {
                // Add namespace the class is defined in
                CodeNamespace classNamespace = new CodeNamespace(classData.Namespace);
                result.Namespaces.Add(classNamespace);
                classNamespace.Types.Add(classDeclaration);
            }
            else
            {
                // Add class to global namespace
                globalNamespace.Types.Add(classDeclaration);
            }
 
            return result;
        }
 
        static CodeAttributeDeclaration GeneratedCodeAttribute
        {
            get
            {
                if (generatedCodeAttribute == null)
                {
                    AssemblyName assemblyName = new AssemblyName(Assembly.GetExecutingAssembly().FullName);
                    generatedCodeAttribute = new CodeAttributeDeclaration(new CodeTypeReference(typeof(System.CodeDom.Compiler.GeneratedCodeAttribute).FullName),
                        new CodeAttributeArgument(new CodePrimitiveExpression(assemblyName.Name)),
                        new CodeAttributeArgument(new CodePrimitiveExpression(assemblyName.Version.ToString())));
                }
 
                return generatedCodeAttribute;
            }
        }
 
        CodeTypeDeclaration GenerateClass(ClassData classData)
        {
            CodeTypeDeclaration result = GenerateClassDeclaration(classData);
 
            result.Members.Add(new CodeMemberField() { Name = "_contentLoaded", Type = new CodeTypeReference(typeof(bool)) });
 
            // Generate fields that match x:Name objects
            var fields = classData.NamedObjects;
            var memberFields = new List<CodeMemberField>();
            foreach (NamedObject field in fields)
            {
                CodeMemberField fieldMember = GenerateField(field, classData);
                memberFields.Add(fieldMember);
                result.Members.Add(fieldMember);
            }
 
            // Generate properties
            if (classData.Properties != null)
            {
                foreach (PropertyData property in classData.Properties)
                {
                    CodeTypeMember[] propertyMembers = GenerateProperty(property, classData);
                    result.Members.AddRange(propertyMembers);
                }
            }
 
            // Generate all x:Code
            foreach (string code in classData.CodeSnippets)
            {
                CodeSnippetTypeMember codeSnippet = new CodeSnippetTypeMember(code);
                result.Members.Add(codeSnippet);
            }
 
            // Generate InitializeComponent method 
            CodeMemberMethod initializeMethod = GenerateInitializeMethod(classData, memberFields);
            result.Members.Add(initializeMethod);
 
            // Generate Before/AfterInitializeComponent partial methods
            if (ArePartialMethodsSupported())
            {
                result.Members.AddRange(GeneratePartialMethods());
            }
 
            // Generate helper method to look up assembly resources
            result.Members.Add(GenerateFindResourceMethod(classData));
 
            // Generate ISupportInitialize implementation
            result.BaseTypes.Add(new CodeTypeReference(typeof(ISupportInitialize)));
            result.Members.AddRange(GenerateISupportInitializeImpl(initializeMethod));
 
            // Generate public parameterless constructor if user-provided source file does not exist
            if (!classData.SourceFileExists)
            {
                result.Members.Add(GenerateConstructorImpl(initializeMethod));
            }
 
            return result;
        }
 
 
        CodeTypeDeclaration GenerateClassDeclaration(ClassData classData)
        {
            if (!this.codeDomProvider.IsValidIdentifier(classData.Name))
            {
                throw FxTrace.Exception.AsError(
                    new InvalidOperationException(SR.InvalidIdentifiers(classData.Name)),
                    classData.FileName);
            }
 
            // <%= visibility%> partial class <%= className %> : <%= type %>
            // {
            // }
            //
            CodeTypeDeclaration rootType = new CodeTypeDeclaration()
                {
                    Name = classData.Name,
                    IsPartial = true,
                    TypeAttributes = classData.IsPublic ? TypeAttributes.Public : TypeAttributes.NotPublic
                };
 
            if (classData.Attributes != null && classData.Attributes.Count > 0)
            {
                CodeAttributeDeclarationCollection attributeCollection = GetAttributeDeclarations(classData.Attributes, classData);
                if (attributeCollection != null && attributeCollection.Count > 0)
                {
                    rootType.CustomAttributes.AddRange(attributeCollection);
                }
            }
 
 
            string baseClrTypeName;
            bool isLocal = false;
            if (!XamlBuildTaskServices.TryGetClrTypeName(classData.BaseType, classData.RootNamespace, out baseClrTypeName, out isLocal))
            {
                throw FxTrace.Exception.AsError(
                    new InvalidOperationException(SR.TaskCannotResolveType(XamlBuildTaskServices.GetFullTypeName(classData.BaseType))),
                    classData.FileName);
            }
            classData.RequiresCompilationPass2 |= isLocal;
            rootType.BaseTypes.Add(baseClrTypeName);
 
            Type baseClrType = classData.BaseType.UnderlyingType;
            if (baseClrType != null)
            {
                if (!IsComVisible(baseClrType))
                {
                    CodeAttributeDeclaration comVisibleFalseDeclaration = new CodeAttributeDeclaration("System.Runtime.InteropServices.ComVisible",
                                                                                                       new CodeAttributeArgument(new CodePrimitiveExpression(false)));
                    rootType.CustomAttributes.Add(comVisibleFalseDeclaration);
                }
            }
 
            return rootType;
        }
 
        CodeAttributeDeclarationCollection GetAttributeDeclarations(IList<AttributeData> attributes, ClassData classData)
        {
            CodeAttributeDeclarationCollection attributeCollection = new CodeAttributeDeclarationCollection();
            foreach (AttributeData attrib in attributes)
            {
                string clrTypeName;
                bool isLocal = false;
                if (!XamlBuildTaskServices.TryGetClrTypeName(attrib.Type, classData.RootNamespace, out clrTypeName, out isLocal))
                {
                    throw FxTrace.Exception.AsError(
                        new InvalidOperationException(SR.TaskCannotResolveType(XamlBuildTaskServices.GetFullTypeName(attrib.Type))),
                        classData.FileName);
                }
                classData.RequiresCompilationPass2 |= isLocal;
 
                CodeAttributeArgument[] arguments = new CodeAttributeArgument[attrib.Parameters.Count + attrib.Properties.Count];
                int i;
                for (i = 0; i < attrib.Parameters.Count; i++)
                {
                    arguments[i] = new CodeAttributeArgument(GetCodeExpressionForAttributeArgument(attrib, attrib.Parameters[i], classData));
                }
                foreach (KeyValuePair<string, AttributeParameterData> propertyEntry in attrib.Properties)
                {
                    arguments[i] = new CodeAttributeArgument(propertyEntry.Key, GetCodeExpressionForAttributeArgument(attrib, propertyEntry.Value, classData));
                    i++;
                }
                attributeCollection.Add(new CodeAttributeDeclaration(new CodeTypeReference(clrTypeName), arguments));
            }
            return attributeCollection;
        }
 
        CodeExpression GetCodeExpressionForAttributeArgument(AttributeData attrib, AttributeParameterData paramInfo, ClassData classData)
        {
            CodeExpression codeExp;
            if (paramInfo.IsArray)
            {
                CodeExpression[] codeInitializationArray;
                if (paramInfo.ArrayContents != null && paramInfo.ArrayContents.Count > 0)
                {
                    codeInitializationArray = new CodeExpression[paramInfo.ArrayContents.Count];
                    for (int i = 0; i < paramInfo.ArrayContents.Count; i++)
                    {
                        codeInitializationArray[i] = GetCodeExpressionForAttributeArgument(/* attrib = */ null, paramInfo.ArrayContents[i], classData);
                    }
 
                    codeExp = new CodeArrayCreateExpression(paramInfo.Type.UnderlyingType.GetElementType(), codeInitializationArray);
                }
                else
                {
                    codeExp = new CodeArrayCreateExpression(paramInfo.Type.UnderlyingType.GetElementType());
                }
            }
            else
            {
                if (attrib != null && language.Equals("VB") && string.Equals(attrib.Type.UnderlyingType.FullName, typeof(DefaultValueAttribute).FullName) && paramInfo.Type == null)
                {
                    // 
                    // This is a special case for VB DefaultValueAttribute because by default the VB compiler does not compile the following code:
                    // 
                    // < System.ComponentModel.DefaultValueAttribute(Nothing) >
                    // 
                    // VB compiler complained that code has multiple interpretation because DefaultValueAttribute has multiple constructors that accept null.
                    // 
                    // The solution here is to just pick the one that take in an object as a parameter. Internally, all these constructor will simply set
                    // an internal field named value to null and therefore picking which one does not matter anyway.
                    // 
                    codeExp = new CodeCastExpression { TargetType = new CodeTypeReference(typeof(object)), Expression = new CodePrimitiveExpression(null) };
                }
                else if (paramInfo.TextValue == null)
                {
                    codeExp = new CodePrimitiveExpression(null);
                }
                else if (typeof(System.Type).IsAssignableFrom(paramInfo.Type.UnderlyingType))
                {
                    codeExp = new CodeTypeOfExpression(paramInfo.TextValue);
                }
                else if (paramInfo.Type.UnderlyingType == typeof(String))
                {
                    codeExp = new CodePrimitiveExpression(paramInfo.TextValue);
                }
                else if (paramInfo.Type.UnderlyingType == typeof(bool))
                {
                    if (paramInfo.TextValue == "true")
                    {
                        codeExp = new CodePrimitiveExpression(true);
                    }
                    else
                    {
                        codeExp = new CodePrimitiveExpression(false);
                    }
                }
                else
                {
                    codeExp = new CodeSnippetExpression(paramInfo.TextValue);
                }
            }
            return codeExp;
        }
 
        bool IsComVisible(Type t)
        {
            IList<CustomAttributeData> cads = CustomAttributeData.GetCustomAttributes(t);
 
            bool found = false;
            bool visible = false;
 
            foreach (var cad in cads)
            {
                if (cad.Constructor.DeclaringType == typeof(ComVisibleAttribute))
                {
                    found = true;
                    visible = (bool)cad.ConstructorArguments[0].Value;
 
                    if (!visible)
                    {
                        return false;
                    }
                }
            }
 
            if (found)
            {
                return true;
            }
 
            cads = CustomAttributeData.GetCustomAttributes(t.Assembly);
 
            foreach (var cad in cads)
            {
                if (cad.Constructor.DeclaringType == typeof(ComVisibleAttribute))
                {
                    found = true;
                    visible = (bool)cad.ConstructorArguments[0].Value;
 
                    if (!visible)
                    {
                        return false;
                    }
                }
            }
 
            return true;
        }
 
        private CodeMemberField GenerateField(NamedObject fieldData, ClassData classData)
        {
            CodeTypeReference fieldCodeType = null;
 
            if (!GetCodeTypeReferenceFromXamlType(fieldData.Type, classData, out fieldCodeType))
            {
                throw FxTrace.Exception.AsError(
                    new InvalidOperationException(SR.TaskCannotResolveFieldType(XamlBuildTaskServices.GetFullTypeName(fieldData.Type), fieldData.Name)),
                    classData.FileName);
            }
 
            if (!this.codeDomProvider.IsValidIdentifier(fieldData.Name))
            {
                throw FxTrace.Exception.AsError(new InvalidOperationException(SR.InvalidIdentifiers(fieldData.Name)),
                    classData.FileName);
            }
 
            //     <%= fieldData.Visibility %> WithEvents <%= fieldData.Type %> <%= fieldData.Name %>;
            //
            CodeMemberField field = new CodeMemberField()
                {
                    Name = fieldData.Name,
                    Type = fieldCodeType,
                    Attributes = GetMemberAttributes(fieldData.Visibility)
                };
            field.UserData["WithEvents"] = true;
            return field;
        }
 
        CodeMemberMethod GenerateInitializeMethod(ClassData classData, List<CodeMemberField> memberFields)
        {
            // /// <summary> InitializeComponent </summary>
            // [DebuggerNonUserCodeAttribute]
            // [System.CodeDom.Compiler.GeneratedCodeAttribute("<%= AssemblyName %>", "<%= AssemblyVersion %>")]
            // public void InitializeComponent() {
            //
            CodeMemberMethod initializeMethod = new CodeMemberMethod()
                {
                    Name = "InitializeComponent",
                    Attributes = MemberAttributes.Public | MemberAttributes.Final,
                    CustomAttributes =
                    {
                        new CodeAttributeDeclaration(new CodeTypeReference(typeof(DebuggerNonUserCodeAttribute))),
                        GeneratedCodeAttribute
                    }
                };
 
            initializeMethod.Comments.AddRange(GenerateXmlComments(initializeMethod.Name));
 
            // if (__contentLoaded) { return; }
            initializeMethod.Statements.Add(
                new CodeConditionStatement()
                {
                    Condition = new CodeBinaryOperatorExpression()
                    {
                        Left = new CodeFieldReferenceExpression() { FieldName = "_contentLoaded", TargetObject = new CodeThisReferenceExpression() },
                        Operator = CodeBinaryOperatorType.ValueEquality,
                        Right = new CodePrimitiveExpression(true)
                    },
                    TrueStatements = {
                        new CodeMethodReturnStatement()
                    }
                }
                );
 
            // __contentLoaded = true;
            initializeMethod.Statements.Add(
                new CodeAssignStatement()
                {
                    Left = new CodeFieldReferenceExpression() { FieldName = "_contentLoaded", TargetObject = new CodeThisReferenceExpression() },
                    Right = new CodePrimitiveExpression(true)
                }
                );
 
            if (ArePartialMethodsSupported())
            {
                // bool isInitialized = false;
                // BeforeInitializeComponent(ref isInitialized);
                // if (isInitialized) {
                //    AfterInitializeComponent();
                //    return;
                // }
                initializeMethod.Statements.Add(new CodeVariableDeclarationStatement(
                    typeof(bool), "isInitialized", new CodePrimitiveExpression(false)));
                initializeMethod.Statements.Add(new CodeMethodInvokeExpression(
                    new CodeThisReferenceExpression(), "BeforeInitializeComponent",
                    new CodeDirectionExpression(FieldDirection.Ref, new CodeVariableReferenceExpression("isInitialized"))
                ));
                initializeMethod.Statements.Add(
                    new CodeConditionStatement
                    {
                        Condition = new CodeBinaryOperatorExpression(
                            new CodeVariableReferenceExpression("isInitialized"),
                            CodeBinaryOperatorType.ValueEquality,
                            new CodePrimitiveExpression(true)
                        ),
                        TrueStatements =
                        {
                            new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), "AfterInitializeComponent"),
                            new CodeMethodReturnStatement()
                        }
                    }
                );
            }
 
            //     string resourceName = FindResource();
            CodeVariableReferenceExpression resourceNameVar =
                initializeMethod.Statements.DeclareVar(
                typeof(string),
                "resourceName",
                new CodeMethodInvokeExpression()
                {
                    Method =
                    new CodeMethodReferenceExpression()
                    {
                        MethodName = "FindResource",
                        TargetObject = new CodeThisReferenceExpression(),
                    },
                }
                );
 
            //     Stream initializeXaml = typeof(<%= className %>).Assembly.GetManifestResourceStream(resourceName);
            //
            CodeVariableReferenceExpression initializeXamlVar =
                initializeMethod.Statements.DeclareVar(
                typeof(Stream),
                "initializeXaml",
                new CodeMethodInvokeExpression()
                {
                    Method =
                    new CodeMethodReferenceExpression()
                    {
                        MethodName = "GetManifestResourceStream",
                        TargetObject =
                        new CodePropertyReferenceExpression()
                        {
                            PropertyName = "Assembly",
                            TargetObject =
                            new CodeTypeOfExpression()
                            {
                                Type = new CodeTypeReference(classData.Name)
                            }
                        }
                    },
                    Parameters =
                    {
                        new CodeVariableReferenceExpression(resourceNameVar.VariableName),
                    }
                }
                );
 
            //     var reader = new System.Xaml.XamlXmlReader(new System.IO.StreamReader(initializeXaml));
            //
            CodeVariableReferenceExpression xmlReaderVar = initializeMethod.Statements.DeclareVar(
                typeof(XmlReader), "xmlReader", new CodePrimitiveExpression(null));
 
            CodeVariableReferenceExpression xamlReaderVar = initializeMethod.Statements.DeclareVar(
                typeof(XamlReader), "reader", new CodePrimitiveExpression(null));
 
            CodeVariableReferenceExpression objWriterVar = initializeMethod.Statements.DeclareVar(
                typeof(XamlObjectWriter), "objectWriter", new CodePrimitiveExpression(null));
 
            // Enclose in try finally block
            // This is to call Dispose on the xmlReader in the finally block, which is the CodeDom way of the C# "using" block
            CodeTryCatchFinallyStatement tryCatchFinally = new CodeTryCatchFinallyStatement();
            tryCatchFinally.TryStatements.AddRange(GetInitializeMethodTryStatements(xmlReaderVar, xamlReaderVar, objWriterVar, initializeXamlVar, classData, memberFields));
            tryCatchFinally.FinallyStatements.AddRange(GetInitializeMethodFinallyStatements(xmlReaderVar, xamlReaderVar, objWriterVar));
            initializeMethod.Statements.Add(tryCatchFinally);
 
            if (ArePartialMethodsSupported())
            {
                // AfterInitializeComponent();
                initializeMethod.Statements.Add(new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), "AfterInitializeComponent"));
            }
 
            return initializeMethod;
        }
 
        CodeStatementCollection GetInitializeMethodTryStatements(CodeExpression xmlReaderVar, CodeExpression xamlReaderVar, CodeExpression objWriterVar,
            CodeExpression initializeXamlVar, ClassData classData, List<CodeMemberField> memberFields)
        {
            CodeStatementCollection tryStatements = new CodeStatementCollection();
 
            // System.Xaml.XamlSchemaContext schemaContext = _XamlStaticHelperNamespace._XamlStaticHelper.SchemaContext;
            CodeVariableReferenceExpression SchemaContextReference = new CodeVariableReferenceExpression(classData.HelperClassFullName + ".SchemaContext");
            CodeVariableReferenceExpression SchemaContext = tryStatements.DeclareVar(typeof(XamlSchemaContext), "schemaContext", SchemaContextReference);
 
            //    xmlReader = System.Xml.XmlReader.Create(initializeXaml);
            CodeExpression xmlReader = new CodeMethodInvokeExpression(
                new CodeMethodReferenceExpression()
                {
                    MethodName = "System.Xml.XmlReader.Create"
                },
                initializeXamlVar);
            tryStatements.Add(new CodeAssignStatement(xmlReaderVar, xmlReader));
 
            //   System.Xaml.XamlXmlReaderSettings readerSettings = new System.Xaml.XamlXmlReaderSettings();
            CodeVariableReferenceExpression readerSettingsVar = tryStatements.DeclareVar(
                    typeof(XamlXmlReaderSettings), "readerSettings", typeof(XamlXmlReaderSettings).New());
 
            //  readerSettings.LocalAssembly = System.Reflection.Assembly.GetExecutingAssembly();
            tryStatements.Add(
                new CodeAssignStatement(
                    new CodePropertyReferenceExpression(readerSettingsVar, "LocalAssembly"),
                    new CodeMethodInvokeExpression(
                       new CodeMethodReferenceExpression()
                       {
                           MethodName = "System.Reflection.Assembly.GetExecutingAssembly"
                       })));
 
            //  readerSettings.AllowProtectedMembersOnRoot = true;
            tryStatements.Add(
                new CodeAssignStatement(
                    new CodePropertyReferenceExpression(readerSettingsVar, "AllowProtectedMembersOnRoot"),
                    new CodePrimitiveExpression(true)));
 
            //  reader = new System.Xaml.XamlXmlReader(xmlReader, schemaContext, readerSettings);
            CodeExpression newReader = typeof(XamlXmlReader).New(xmlReaderVar, SchemaContext, readerSettingsVar);
            tryStatements.Add(new CodeAssignStatement(xamlReaderVar, newReader));
 
            //     XamlObjectWriterSettings writerSettings = new XamlObjectWriterSettings();
            CodeVariableReferenceExpression writerSettingsVar = tryStatements.DeclareVar(
                typeof(XamlObjectWriterSettings), "writerSettings", typeof(XamlObjectWriterSettings).New());
 
            //  writerSettings.RootObjectInstance = this;
            tryStatements.Add(new CodeAssignStatement()
            {
                Left = writerSettingsVar.Property("RootObjectInstance"),
                Right = CodeThis
            });
 
            //  writerSettings.AccessLevel = System.Xaml.Permissions.XamlAccessLevel.PrivateAccessTo(typeof(<TypeBeingGenerated>));
            tryStatements.Add(new CodeAssignStatement()
            {
                Left = writerSettingsVar.Property("AccessLevel"),
                Right = new CodeMethodInvokeExpression(
                            new CodeMethodReferenceExpression()
                            {
                                MethodName = "System.Xaml.Permissions.XamlAccessLevel.PrivateAccessTo"
                            },
                            new CodeTypeOfExpression(classData.Name)
                        )
            });
 
            //     var writer = new XamlObjectWriter(schemaContext, settings);
            //
            CodeExpression newObjectWriter = typeof(XamlObjectWriter).New(SchemaContext, writerSettingsVar);
            tryStatements.Add(new CodeAssignStatement(objWriterVar, newObjectWriter));
 
            //      XamlServices.Transform(reader, writer);
            //
            tryStatements.Add(
                    new CodeMethodInvokeExpression(
                        new CodeMethodReferenceExpression()
                        {
                            MethodName = "System.Xaml.XamlServices.Transform"
                        },
                        xamlReaderVar,
                        objWriterVar
                    ));
 
            //  For all fields generated, generate the wireup to get the value from xaml. For eg, for a field of type "Bar" and name "Baz":
            //  Baz = ((Tests.Build.Tasks.Xaml.Bar)(objectWriter.RootNameScope.FindName("Baz")));
            if (memberFields != null && memberFields.Count > 0)
            {
                foreach (var field in memberFields)
                {
                    tryStatements.Add(
                        new CodeAssignStatement(
                            new CodeVariableReferenceExpression(field.Name),
                            new CodeCastExpression(
                                field.Type,
                                new CodeMethodInvokeExpression(
                                    new CodePropertyReferenceExpression(objWriterVar, "RootNameScope"),
                                    "FindName",
                                    new CodePrimitiveExpression(field.Name)))));
 
                }
            }
 
            return tryStatements;
        }
 
        CodeStatementCollection GetInitializeMethodFinallyStatements(CodeExpression xmlReaderVar, CodeExpression xamlReaderVar, CodeExpression objWriterVar)
        {
            CodeStatementCollection finallyStatements = new CodeStatementCollection();
 
            CodeConditionStatement xmlReaderNotNull = new CodeConditionStatement();
            xmlReaderNotNull.Condition = new CodeBinaryOperatorExpression(xmlReaderVar, CodeBinaryOperatorType.IdentityInequality,
                new CodePrimitiveExpression(null));
            CodeCastExpression iDisposibleCastXmlReader = new CodeCastExpression(typeof(IDisposable), xmlReaderVar);
            xmlReaderNotNull.TrueStatements.Add(new CodeMethodInvokeExpression(iDisposibleCastXmlReader, "Dispose"));
            finallyStatements.Add(xmlReaderNotNull);
 
            CodeConditionStatement xamlReaderNotNull = new CodeConditionStatement();
            xamlReaderNotNull.Condition = new CodeBinaryOperatorExpression(xamlReaderVar, CodeBinaryOperatorType.IdentityInequality,
                new CodePrimitiveExpression(null));
            CodeCastExpression iDisposibleCastXamlReader = new CodeCastExpression(typeof(IDisposable), xamlReaderVar);
            xamlReaderNotNull.TrueStatements.Add(new CodeMethodInvokeExpression(iDisposibleCastXamlReader, "Dispose"));
            finallyStatements.Add(xamlReaderNotNull);
 
            CodeConditionStatement objWriterNotNull = new CodeConditionStatement();
            objWriterNotNull.Condition = new CodeBinaryOperatorExpression(objWriterVar, CodeBinaryOperatorType.IdentityInequality,
                new CodePrimitiveExpression(null));
            CodeCastExpression iDisposibleCastObjWriter = new CodeCastExpression(typeof(IDisposable), objWriterVar);
            objWriterNotNull.TrueStatements.Add(new CodeMethodInvokeExpression(iDisposibleCastObjWriter, "Dispose"));
            finallyStatements.Add(objWriterNotNull);
 
            return finallyStatements;
        }
 
        // CodeDOM has no language-independent support for partial methods
        bool ArePartialMethodsSupported()
        {
            return string.Equals(this.language, "C#", StringComparison.OrdinalIgnoreCase) ||
                string.Equals(this.language, "VB", StringComparison.OrdinalIgnoreCase);
        }
 
        [SuppressMessage(FxCop.Category.Globalization, FxCop.Rule.DoNotPassLiteralsAsLocalizedParameters,
            Justification = "The string literals are code snippets, not localizable values.")]
        CodeTypeMember[] GeneratePartialMethods()
        {
            if (string.Equals(this.language, "C#", StringComparison.OrdinalIgnoreCase))
            {
                return new CodeTypeMember[]
                {
                    new CodeSnippetTypeMember("partial void BeforeInitializeComponent(ref bool isInitialized);\r\n"),
                    new CodeSnippetTypeMember("partial void AfterInitializeComponent();\r\n"),
                };
            }
 
            if (string.Equals(this.language, "VB", StringComparison.OrdinalIgnoreCase))
            {
                return new CodeTypeMember[]
                {
                    new CodeSnippetTypeMember("Partial Private Sub BeforeInitializeComponent(ByRef isInitialized as Boolean)\r\nEnd Sub\r\n"),
                    new CodeSnippetTypeMember("Partial Private Sub AfterInitializeComponent\r\nEnd Sub\r\n"),
                };
            }
 
            throw Fx.AssertAndThrow("GeneratePartialMethods should not be called if ArePartialMethodsSupported returns false.");
        }
 
        CodeMemberMethod GenerateFindResourceMethod(ClassData classData)
        {
            //     [System.CodeDom.Compiler.GeneratedCodeAttribute("<%= AssemblyName %>", "<%= AssemblyVersion %>")]
            //     private string FindResource() {
            //
            CodeMemberMethod findResourceMethod = new CodeMemberMethod()
                {
                    Name = "FindResource",
                    Attributes = MemberAttributes.Private | MemberAttributes.Final,
                    ReturnType = new CodeTypeReference(typeof(string)),
                    CustomAttributes = { GeneratedCodeAttribute }
                };
 
            //     string[] resources = typeof(<%= className %>).Assembly.GetManifestResourceNames();
            //
            CodeVariableReferenceExpression resourcesVar =
                findResourceMethod.Statements.DeclareVar(
                typeof(string[]),
                "resources",
                new CodeMethodInvokeExpression()
                {
                    Method =
                    new CodeMethodReferenceExpression()
                    {
                        MethodName = "GetManifestResourceNames",
                        TargetObject =
                        new CodePropertyReferenceExpression()
                        {
                            PropertyName = "Assembly",
                            TargetObject =
                            new CodeTypeOfExpression()
                            {
                                Type = new CodeTypeReference(classData.Name)
                            }
                        }
                    },
                }
                );
 
            // for (int i = 0; i < resources.Length; i++) {
            //     string resource = resources[i];
            //     if (resource.Contains(searchString)) {
            //         return resource;
            //     }
            // }
            findResourceMethod.Statements.Add(
                new CodeIterationStatement()
                {
                    InitStatement = new CodeVariableDeclarationStatement()
                    {
                        Type = new CodeTypeReference(typeof(int)),
                        Name = "i",
                        InitExpression = new CodePrimitiveExpression(0),
                    },
                    TestExpression = new CodeBinaryOperatorExpression()
                    {
                        Left = new CodeVariableReferenceExpression("i"),
                        Operator = CodeBinaryOperatorType.LessThan,
                        Right = new CodePropertyReferenceExpression()
                        {
                            TargetObject = new CodeVariableReferenceExpression(resourcesVar.VariableName),
                            PropertyName = "Length",
                        },
                    },
                    IncrementStatement = new CodeAssignStatement()
                    {
                        Left = new CodeVariableReferenceExpression("i"),
                        Right = new CodeBinaryOperatorExpression()
                        {
                            Left = new CodeVariableReferenceExpression("i"),
                            Operator = CodeBinaryOperatorType.Add,
                            Right = new CodePrimitiveExpression(1),
                        }
                    },
                    Statements = {
                        new CodeVariableDeclarationStatement()
                        {
                            Type = new CodeTypeReference(typeof(string)),
                            Name = "resource",
                            InitExpression = new CodeArrayIndexerExpression(
                            new CodeVariableReferenceExpression(resourcesVar.VariableName),
                            new CodeVariableReferenceExpression("i")),
                        },
                        new CodeConditionStatement()
                        {
                            Condition = new CodeBinaryOperatorExpression()
                            {
                                Left = new CodeMethodInvokeExpression()
                                {
                                    Method = new CodeMethodReferenceExpression()
                                    {
                                        TargetObject = new CodeVariableReferenceExpression("resource"),
                                        MethodName = "Contains",
                                    },
                                    Parameters = { new CodePrimitiveExpression("." + classData.EmbeddedResourceFileName), },
                                },
                                Operator = CodeBinaryOperatorType.BooleanOr,
                                Right = new CodeMethodInvokeExpression()
                                {
                                    Method = new CodeMethodReferenceExpression()
                                    {
                                        TargetObject = new CodeVariableReferenceExpression("resource"),
                                        MethodName = "Equals",
                                    },
                                    Parameters = {
                                        new CodePrimitiveExpression(classData.EmbeddedResourceFileName),
                                    },
                                }                                   
                            },
                            TrueStatements = {
                                new CodeMethodReturnStatement()
                                {
                                    Expression = new CodeVariableReferenceExpression("resource"),
                                }
                            }
                        }
                    },
                }
                );
 
            // throw new InvalidOperationException("Resource not found.");
            //
            findResourceMethod.Statements.Add(
                new CodeThrowExceptionStatement()
                {
                    ToThrow =
                    new CodeObjectCreateExpression()
                    {
                        CreateType = new CodeTypeReference(typeof(InvalidOperationException)),
                        Parameters =
                        {
                            new CodePrimitiveExpression("Resource not found."),
                        }
                    }
                }
                );
 
            return findResourceMethod;
        }
 
        CodeTypeMember[] GenerateISupportInitializeImpl(CodeMemberMethod initializeMethod)
        {
            CodeTypeReference ifaceType = new CodeTypeReference(typeof(ISupportInitialize));
 
            // Suppress Code Analysis violation errors arising from defining interface methods explicitly.
            //
            CodeAttributeArgument[] suppressMessageArguments = { 
                                                                   new CodeAttributeArgument(new CodePrimitiveExpression("Microsoft.Design")), 
                                                                   new CodeAttributeArgument(new CodePrimitiveExpression("CA1033")) 
                                                               };
            CodeAttributeDeclaration suppressMessageDeclaration = new CodeAttributeDeclaration("System.Diagnostics.CodeAnalysis.SuppressMessage", suppressMessageArguments);
 
            //    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1033")]
            //    [System.CodeDom.Compiler.GeneratedCodeAttribute("<%= AssemblyName %>", "<%= AssemblyVersion %>")]
            //    void ISupportInitialize.BeginInit() {}
            //
            CodeMemberMethod beginMethod = new CodeMemberMethod()
                {
                    PrivateImplementationType = ifaceType,
                    Name = "BeginInit",
                };
            beginMethod.CustomAttributes.Add(suppressMessageDeclaration);
            beginMethod.CustomAttributes.Add(GeneratedCodeAttribute);
 
            //    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1033")]
            //    [System.CodeDom.Compiler.GeneratedCodeAttribute("<%= AssemblyName %>", "<%= AssemblyVersion %>")]
            //    void ISupportInitialize.EndInit()
            //    {
            //        this.InitializeComponent();
            //    }
            //
            CodeMemberMethod endMethod = new CodeMemberMethod()
                {
                    PrivateImplementationType = ifaceType,
                    Name = "EndInit",
                    Statements = { CodeThis.Invoke(initializeMethod.Name) },
                };
            endMethod.CustomAttributes.Add(suppressMessageDeclaration);
            endMethod.CustomAttributes.Add(GeneratedCodeAttribute);
 
            return new CodeMemberMethod[] { beginMethod, endMethod };
        }
 
        CodeConstructor GenerateConstructorImpl(CodeMemberMethod initializeMethod)
        {
            // [System.CodeDom.Compiler.GeneratedCodeAttribute("<%= AssemblyName %>", "<%= AssemblyVersion %>")]
            // public <%= className %>()
            //    {
            //        this.InitializeComponent();
            //    }
            //
            CodeConstructor constructor = new CodeConstructor()
                {
                    Attributes = MemberAttributes.Public,
                    Statements = { CodeThis.Invoke(initializeMethod.Name) },
                    CustomAttributes = { GeneratedCodeAttribute }
                };
 
            return constructor;
        }
 
        CodeTypeMember[] GenerateProperty(PropertyData property, ClassData classData)
        {
            // 
 
            CodeTypeReference propertyCodeType = null;
 
            if (!GetCodeTypeReferenceFromXamlType(property.Type, classData, out propertyCodeType))
            {
                throw FxTrace.Exception.AsError(new InvalidOperationException(SR.TaskCannotResolvePropertyType(
                    XamlBuildTaskServices.GetFullTypeName(property.Type), property.Name)), classData.FileName);
            }
 
            if (!this.codeDomProvider.IsValidIdentifier(property.Name))
            {
                throw FxTrace.Exception.AsError(
                    new InvalidOperationException(SR.InvalidIdentifiers(property.Name)),
                    classData.FileName);
            }
 
            //     private <%= property.Type %> _<%= property.Name %>;
            //
            CodeMemberField fieldMember = new CodeMemberField()
                {
                    Attributes = MemberAttributes.Private,
                    Name = "_" + property.Name,
                    Type = propertyCodeType
                };
 
            //    public <%= property.Type %> <%= property.Name %> {
            //       get { return this._<%= property.Name %>; }
            //       set { this._<%= property.Name %> = value; }
            //    }
            //
            CodeMemberProperty propertyMember = new CodeMemberProperty()
                {
                    Attributes = MemberAttributes.Final,
                    Name = property.Name,
                    Type = propertyCodeType,
                    GetStatements =
                    {
                        new CodeMethodReturnStatement(CodeThis.Field(fieldMember.Name))
                    },
                    SetStatements =
                    {
                        new CodeAssignStatement()
                        {
                            Left = CodeThis.Field(fieldMember.Name),
                            Right = new CodeVariableReferenceExpression("value")
                        }
                    }
                };
            propertyMember.Attributes |= GetMemberAttributes(property.Visibility);
 
            if (property.Attributes != null && property.Attributes.Count > 0)
            {
                CodeAttributeDeclarationCollection attributeCollection = GetAttributeDeclarations(property.Attributes, classData);
                if (attributeCollection != null && attributeCollection.Count > 0)
                {
                    propertyMember.CustomAttributes.AddRange(attributeCollection);
                }
            }
 
            return new CodeTypeMember[] { fieldMember, propertyMember };
        }
 
        bool GetCodeTypeReferenceFromXamlType(XamlType xamlType, ClassData classData, out CodeTypeReference codeTypeReference)
        {
            codeTypeReference = null;
            string propClrTypeName;
            bool isLocal = false;
            if (!XamlBuildTaskServices.TryGetClrTypeName(xamlType, classData.RootNamespace, out propClrTypeName, out isLocal))
            {
                return false;
            }
            classData.RequiresCompilationPass2 |= isLocal;
 
            codeTypeReference = new CodeTypeReference(propClrTypeName);
            if (!GetTypeArgumentFromXamlType(codeTypeReference, xamlType, classData))
            {
                return false;
            }
            return true;
        }
 
        bool GetTypeArgumentFromXamlType(CodeTypeReference codeTypeReference, XamlType xamlType, ClassData classData)
        {
            //
            // Depending on the name passed into the CodeTypeReference 
            // constructor the type args may already be populated
            if (codeTypeReference.TypeArguments != null && codeTypeReference.TypeArguments.Count == 0 &&
                xamlType.TypeArguments != null && xamlType.TypeArguments.Count > 0)
            {
                foreach (XamlType argumentTypeReference in xamlType.TypeArguments)
                {
                    CodeTypeReference argumentCodeTypeReference = null;
                    if (!GetCodeTypeReferenceFromXamlType(argumentTypeReference, classData, out argumentCodeTypeReference))
                    {
                        return false;
                    }
                    codeTypeReference.TypeArguments.Add(argumentCodeTypeReference);
                }
            }
 
            return true;
        }
 
        [SuppressMessage(FxCop.Category.Globalization, "CA1303",
            Justification = "Literals are used as comments in generated code.")]
        private CodeCommentStatement[] GenerateXmlComments(string comment)
        {
            //     /// <summary>
            //     /// <%= comment %>
            //     /// </summary>
            return new CodeCommentStatement[] {
                    new CodeCommentStatement("<summary>", true),
                    new CodeCommentStatement(comment, true),
                    new CodeCommentStatement("</summary>", true)
                };
        }
 
        MemberAttributes GetMemberAttributes(MemberVisibility visibility)
        {
            switch (visibility)
            {
                case MemberVisibility.Private:
                    return MemberAttributes.Private;
                case MemberVisibility.Public:
                    return MemberAttributes.Public;
                case MemberVisibility.Family:
                    return MemberAttributes.Family;
                case MemberVisibility.Assembly:
                    return MemberAttributes.Assembly;
                case MemberVisibility.FamilyOrAssembly:
                    return MemberAttributes.FamilyOrAssembly;
                case MemberVisibility.FamilyAndAssembly:
                    return MemberAttributes.FamilyAndAssembly;
                default:
                    throw Fx.AssertAndThrow("Invalid MemberVisibility value");
            }
        }
 
        public CodeCompileUnit GenerateHelperClass(string namespaceName, string className, IList<Assembly> loadedAssemblyList)
        {
 
            CodeCompileUnit result = new CodeCompileUnit();
 
            // Add global namespace
            CodeNamespace classNamespace = new CodeNamespace(namespaceName);
            result.Namespaces.Add(classNamespace);
 
            CodeTypeDeclaration classDeclaration = GenerateHelperClassBody(className, loadedAssemblyList);
            classDeclaration.CustomAttributes.Add(GeneratedCodeAttribute);
            classNamespace.Types.Add(classDeclaration);
 
            return result;
        }
 
        CodeTypeDeclaration GenerateHelperClassBody(string className, IList<Assembly> loadedAssemblyList)
        {
            // <%= visibility%> partial class <%= className %> : <%= type %>
            // {
            // }
            //
            CodeTypeDeclaration result = new CodeTypeDeclaration()
            {
                Name = className,
                TypeAttributes = TypeAttributes.NotPublic,
            };
 
            CodeTypeMember[] schemaContextMembers = GenerateSchemaContext();
            result.Members.AddRange(schemaContextMembers);
 
            CodeTypeMember[] assemblyListMembers = GenerateAssemblyListProperty();
            result.Members.AddRange(assemblyListMembers);
 
            // Generate helper Loadassembly method to go through all the assemblies and load them
            result.Members.Add(GenerateLoadAssembliesMethod(loadedAssemblyList));
 
            // Generate helper load to load assemblies correctly
            result.Members.Add(GenerateLoadMethod());
 
            return result;
        }
 
        CodeTypeMember[] GenerateAssemblyListProperty()
        {
            ////Generate the following code:
 
            //private static System.Collections.Generic.IList<System.Reflection.Assembly> assemblyListField;
            //internal static System.Collections.Generic.IList<System.Reflection.Assembly> AssemblyList {
            //    get {
            //        if ((assemblyListField == null)) {
            //            assemblyListField = LoadAssemblies();
            //        }
            //        return assemblyListField;
            //    }
            //}
 
            CodeMemberField assemblyListField = new CodeMemberField()
            {
                Name = "assemblyListField",
                Type = new CodeTypeReference(typeof(IList<Assembly>)),
                Attributes = MemberAttributes.Private | MemberAttributes.Static
            };
            CodeVariableReferenceExpression assemblyList = new CodeVariableReferenceExpression("assemblyListField");
 
            CodeMemberProperty AssemblyList = new CodeMemberProperty()
            {
                Name = "AssemblyList",
                Type = new CodeTypeReference(typeof(IList<Assembly>)),
                Attributes = MemberAttributes.Assembly | MemberAttributes.Static,
            };
 
            CodeConditionStatement assemblyListNull = new CodeConditionStatement(
                new CodeBinaryOperatorExpression(assemblyList, CodeBinaryOperatorType.IdentityEquality, new CodePrimitiveExpression(null)),
                new CodeAssignStatement(assemblyList,
                    new CodeMethodInvokeExpression { Method = new CodeMethodReferenceExpression { MethodName = "LoadAssemblies" } }));
            AssemblyList.GetStatements.Add(assemblyListNull);
            AssemblyList.GetStatements.Add(new CodeMethodReturnStatement(assemblyList));
 
            return new CodeTypeMember[] { assemblyListField, AssemblyList };
        }
 
        CodeTypeMember[] GenerateSchemaContext()
        {
            ////Generate the following code:
 
            //private static System.WeakReference schemaContextField;
            //internal static System.Xaml.XamlSchemaContext SchemaContext {
            //get {
            //    System.Xaml.XamlSchemaContext xsc = null;
            //    if ((schemaContextField != null)) {
            //        xsc = ((System.Xaml.XamlSchemaContext)(schemaContextField.Target));
            //        if ((xsc != null)) {
            //            return xsc;
            //        }
            //    }
            //    if ((AssemblyList.Count > 0)) {
            //        xsc = new System.Xaml.XamlSchemaContext(AssemblyList);
            //    }
            //    else {
            //        xsc = new System.Xaml.XamlSchemaContext();
            //    }
            //    schemaContextField = new System.WeakReference(xsc);
            //    return xsc;
            //}
 
 
            CodeMemberField schemaContextField = new CodeMemberField()
            {
                Name = "schemaContextField",
                Type = new CodeTypeReference(typeof(WeakReference)),
                Attributes = MemberAttributes.Private | MemberAttributes.Static,
            };
            CodeVariableReferenceExpression schemaContext = new CodeVariableReferenceExpression("schemaContextField");
 
            CodeMemberProperty SchemaContext = new CodeMemberProperty()
            {
                Name = "SchemaContext",
                Type = new CodeTypeReference(typeof(XamlSchemaContext)),
                Attributes = MemberAttributes.Assembly | MemberAttributes.Static,
            };
 
            CodeVariableReferenceExpression xsc = SchemaContext.GetStatements.DeclareVar(typeof(XamlSchemaContext), "xsc", new CodePrimitiveExpression(null));
 
            CodeConditionStatement getSchemaContextIfNotNull = new CodeConditionStatement();
            CodeBinaryOperatorExpression schemaContextNotNull = new CodeBinaryOperatorExpression(schemaContext,
                CodeBinaryOperatorType.IdentityInequality,
                new CodePrimitiveExpression(null));
            getSchemaContextIfNotNull.Condition = schemaContextNotNull;
            CodeAssignStatement assignSchemaContext = new CodeAssignStatement(xsc,
                new CodeCastExpression(typeof(XamlSchemaContext), new CodePropertyReferenceExpression(schemaContext, "Target")));
            CodeConditionStatement xscReturnIfNotNull = new CodeConditionStatement(
                new CodeBinaryOperatorExpression(xsc, CodeBinaryOperatorType.IdentityInequality, new CodePrimitiveExpression(null)),
                new CodeMethodReturnStatement(xsc));
            getSchemaContextIfNotNull.TrueStatements.Add(assignSchemaContext);
            getSchemaContextIfNotNull.TrueStatements.Add(xscReturnIfNotNull);
            SchemaContext.GetStatements.Add(getSchemaContextIfNotNull);
 
            CodeVariableReferenceExpression AssemblyList = new CodeVariableReferenceExpression("AssemblyList");
            CodeConditionStatement initSchemaContext = new CodeConditionStatement();
            initSchemaContext.Condition = new CodeBinaryOperatorExpression(
                new CodePropertyReferenceExpression(AssemblyList, "Count"),
                CodeBinaryOperatorType.GreaterThan,
                new CodePrimitiveExpression(0));
            initSchemaContext.TrueStatements.Add(new CodeAssignStatement(xsc, typeof(XamlSchemaContext).New(AssemblyList)));
            initSchemaContext.FalseStatements.Add(new CodeAssignStatement(xsc, typeof(XamlSchemaContext).New()));
            SchemaContext.GetStatements.Add(initSchemaContext);
 
            CodeAssignStatement assignSchemaContextField = new CodeAssignStatement(schemaContext, typeof(WeakReference).New(xsc));
            SchemaContext.GetStatements.Add(assignSchemaContextField);
 
            SchemaContext.GetStatements.Add(new CodeMethodReturnStatement(xsc));
 
            return new CodeTypeMember[] { schemaContextField, SchemaContext };
        }
 
        CodeMemberMethod GenerateLoadMethod()
        {
            ////Generate the following code:
 
            //private static System.Reflection.Assembly Load(string assemblyNameVal) {
            //    System.Reflection.AssemblyName assemblyName = new System.Reflection.AssemblyName(assemblyNameVal);
            //    byte[] publicKeyToken = assemblyName.GetPublicKeyToken();
            //    System.Reflection.Assembly asm = null;
            //    try {
            //        asm = System.Reflection.Assembly.Load(assemblyName.FullName);
            //    }
            //    catch (System.Exception ) {
            //        System.Reflection.AssemblyName shortName = new System.Reflection.AssemblyName(assemblyName.Name);
            //        if ((publicKeyToken != null)) {
            //            shortName.SetPublicKeyToken(publicKeyToken);
            //        }
            //        asm = System.Reflection.Assembly.Load(shortName);
            //    }
            //    return asm;
            //}
 
            CodeMemberMethod loadMethod = new CodeMemberMethod()
            {
                Name = "Load",
                Attributes = MemberAttributes.Private | MemberAttributes.Static,
                ReturnType = new CodeTypeReference(typeof(Assembly))
            };
            loadMethod.Parameters.Add(new CodeParameterDeclarationExpression(typeof(string), "assemblyNameVal"));
            CodeVariableReferenceExpression assemblyNameVal = new CodeVariableReferenceExpression("assemblyNameVal");
 
            CodeExpression initAssemblyName = typeof(AssemblyName).New(assemblyNameVal);
            CodeVariableReferenceExpression assemblyName = loadMethod.Statements.DeclareVar(typeof(AssemblyName), "assemblyName", initAssemblyName);
 
            CodeVariableReferenceExpression publicKeyToken = loadMethod.Statements.DeclareVar(typeof(byte[]),
                "publicKeyToken",
                new CodeMethodInvokeExpression()
                {
                    Method =
                    new CodeMethodReferenceExpression()
                    {
                        MethodName = "GetPublicKeyToken",
                        TargetObject = assemblyName,
                    },
                }
                );
            CodeVariableReferenceExpression asm = loadMethod.Statements.DeclareVar(typeof(Assembly), "asm", new CodePrimitiveExpression(null));
 
            CodeExpression publicKeyTokenNotNullExp = new CodeBinaryOperatorExpression(publicKeyToken,
                CodeBinaryOperatorType.IdentityInequality, new CodePrimitiveExpression(null));
 
            CodeTryCatchFinallyStatement tryCatchExp = new CodeTryCatchFinallyStatement();
 
            tryCatchExp.TryStatements.Add(new CodeAssignStatement(asm,
                new CodeMethodInvokeExpression(
                    new CodeMethodReferenceExpression()
                    {
                        MethodName = "System.Reflection.Assembly.Load"
                    },
                    new CodePropertyReferenceExpression(assemblyName, "FullName")
                )
            ));
 
            CodeCatchClause catchClause = new CodeCatchClause();
            CodeVariableReferenceExpression shortName = catchClause.Statements.DeclareVar(typeof(AssemblyName), "shortName",
                typeof(AssemblyName).New(new CodePropertyReferenceExpression(assemblyName, "Name")));
            CodeConditionStatement setPublicKeyTokenExp = new CodeConditionStatement();
            setPublicKeyTokenExp.Condition = publicKeyTokenNotNullExp;
            setPublicKeyTokenExp.TrueStatements.Add(
                new CodeMethodInvokeExpression(new CodeMethodReferenceExpression(shortName, "SetPublicKeyToken"), publicKeyToken)
            );
            catchClause.Statements.Add(setPublicKeyTokenExp);
            catchClause.Statements.Add(new CodeAssignStatement(asm,
                new CodeMethodInvokeExpression(
                    new CodeMethodReferenceExpression()
                    {
                        MethodName = "System.Reflection.Assembly.Load"
                    },
                    shortName
                )
            ));
            tryCatchExp.CatchClauses.Add(catchClause);
 
            loadMethod.Statements.Add(tryCatchExp);
            loadMethod.Statements.Add(new CodeMethodReturnStatement(asm));
            return loadMethod;
        }
 
        CodeMemberMethod GenerateLoadAssembliesMethod(IEnumerable<Assembly> references)
        {
            //// Generate the following code:
 
            //private static System.Collections.Generic.IList<System.Reflection.Assembly> LoadAssemblies() {
            //    System.Collections.Generic.IList<System.Reflection.Assembly> assemblyList = new System.Collections.Generic.List<System.Reflection.Assembly>();
            //
            //    assemblyList.Add(Load(<%= AssemblyFullName %>);
            //      ...
            //    assemblyList.Add(Assembly.GetExecutingAssembly());
            //    return assemblyList;
            //}
 
            CodeMemberMethod loadAssembliesMethod = new CodeMemberMethod()
            {
                Name = "LoadAssemblies",
                Attributes = MemberAttributes.Private | MemberAttributes.Static,
                ReturnType = new CodeTypeReference(typeof(IList<Assembly>)),
            };
 
            CodeVariableReferenceExpression assemblyList = loadAssembliesMethod.Statements.DeclareVar(typeof(IList<Assembly>),
                "assemblyList", typeof(List<Assembly>).New());
 
            foreach (var reference in references)
            {
                loadAssembliesMethod.Statements.Add(
                    new CodeMethodInvokeExpression(assemblyList, "Add",
                       new CodeMethodInvokeExpression(
                           new CodeMethodReferenceExpression()
                           {
                               MethodName = "Load"
                           },
                           new CodePrimitiveExpression(reference.FullName)
                        )
                    )
                );
            }
 
            loadAssembliesMethod.Statements.Add(
                    new CodeMethodInvokeExpression(assemblyList, "Add",
                       new CodeMethodInvokeExpression(
                           new CodeMethodReferenceExpression()
                           {
                               MethodName = "System.Reflection.Assembly.GetExecutingAssembly"
                           }
                        )
                    )
                );
 
            loadAssembliesMethod.Statements.Add(new CodeMethodReturnStatement(assemblyList));
 
 
            return loadAssembliesMethod;
        }
    }
}