private static void EmitBasicClassMembers(CodeTypeDeclaration srClass, String nameSpace, String baseName, String resourcesNamespace, bool internalClass, bool useStatic)
        {
            const String tmpVarName = "temp";
            String       resMgrCtorParam;

            if (resourcesNamespace != null)
            {
                if (resourcesNamespace.Length > 0)
                {
                    resMgrCtorParam = resourcesNamespace + '.' + baseName;
                }
                else
                {
                    resMgrCtorParam = baseName;
                }
            }
            else if (!string.IsNullOrEmpty(nameSpace))
            {
                resMgrCtorParam = nameSpace + '.' + baseName;
            }
            else
            {
                resMgrCtorParam = baseName;
            }

            var suppressMessageAttrib = new CodeAttributeDeclaration(new CodeTypeReference(typeof(SuppressMessageAttribute)));

            suppressMessageAttrib.AttributeType.Options = CodeTypeReferenceOptions.GlobalReference;
            suppressMessageAttrib.Arguments.Add(new CodeAttributeArgument(new CodePrimitiveExpression("Microsoft.Performance")));
            suppressMessageAttrib.Arguments.Add(new CodeAttributeArgument(new CodePrimitiveExpression("CA1811:AvoidUncalledPrivateCode")));

            // Emit a constructor - make it protected even if it is a "static" class to allow subclassing
            CodeConstructor ctor = new CodeConstructor();

            ctor.CustomAttributes.Add(suppressMessageAttrib);
            if (useStatic || internalClass)
            {
                ctor.Attributes = MemberAttributes.FamilyAndAssembly;
            }
            else
            {
                ctor.Attributes = MemberAttributes.Public;
            }
            srClass.Members.Add(ctor);

            // Emit _resMgr field.
            var ResMgrCodeTypeReference = new CodeTypeReference(typeof(ResourceManager), CodeTypeReferenceOptions.GlobalReference);
            var field = new CodeMemberField(ResMgrCodeTypeReference, ResMgrFieldName)
            {
                Attributes = MemberAttributes.Private
            };

            if (useStatic)
            {
                field.Attributes |= MemberAttributes.Static;
            }
            srClass.Members.Add(field);

            // Emit _resCulture field, and leave it set to null.
            var CultureTypeReference = new CodeTypeReference(typeof(CultureInfo), CodeTypeReferenceOptions.GlobalReference);

            field            = new CodeMemberField(CultureTypeReference, CultureInfoFieldName);
            field.Attributes = MemberAttributes.Private;
            if (useStatic)
            {
                field.Attributes |= MemberAttributes.Static;
            }
            srClass.Members.Add(field);

            // Emit ResMgr property
            CodeMemberProperty resMgr = new CodeMemberProperty();

            srClass.Members.Add(resMgr);
            resMgr.Name   = ResMgrPropertyName;
            resMgr.HasGet = true;
            resMgr.HasSet = false;
            resMgr.Type   = ResMgrCodeTypeReference;
            if (internalClass)
            {
                resMgr.Attributes = MemberAttributes.Assembly;
            }
            else
            {
                resMgr.Attributes = MemberAttributes.Public;
            }
            if (useStatic)
            {
                resMgr.Attributes |= MemberAttributes.Static;
            }

            // Mark the ResMgr property as advanced
            var editorBrowsableStateTypeRef =
                new CodeTypeReference(typeof(System.ComponentModel.EditorBrowsableState))
            {
                Options = CodeTypeReferenceOptions.GlobalReference
            };

            var editorBrowsableStateAdvanced     = new CodeAttributeArgument(new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(editorBrowsableStateTypeRef), "Advanced"));
            var editorBrowsableAdvancedAttribute = new CodeAttributeDeclaration("System.ComponentModel.EditorBrowsableAttribute", editorBrowsableStateAdvanced);

            editorBrowsableAdvancedAttribute.AttributeType.Options = CodeTypeReferenceOptions.GlobalReference;
            resMgr.CustomAttributes.Add(editorBrowsableAdvancedAttribute);

            // Emit the Culture property (read/write)
            var culture = new CodeMemberProperty();

            srClass.Members.Add(culture);
            culture.Name   = CultureInfoPropertyName;
            culture.HasGet = true;
            culture.HasSet = true;
            culture.Type   = CultureTypeReference;
            if (internalClass)
            {
                culture.Attributes = MemberAttributes.Assembly;
            }
            else
            {
                culture.Attributes = MemberAttributes.Public;
            }

            if (useStatic)
            {
                culture.Attributes |= MemberAttributes.Static;
            }

            // Mark the Culture property as advanced
            culture.CustomAttributes.Add(editorBrowsableAdvancedAttribute);

            /*
             * // Here's what I'm trying to emit.  Since not all languages support
             * // try/finally, we'll avoid our double lock pattern here.
             * // This will only hurt perf when we get two threads racing through
             * // this method the first time.  Unfortunate, but not a big deal.
             * // Also, the .NET Compact Framework doesn't support
             * // Thread.MemoryBarrier (they only run on processors w/ a strong
             * // memory model, and who knows about IA64...)
             * // Once we have Interlocked.CompareExchange<T>, we should use it here.
             * if (_resMgr == null) {
             *    ResourceManager tmp = new ResourceManager("<resources-name-with-namespace>", typeof("<class-name>").Assembly);
             *    _resMgr = tmp;
             * }
             * return _resMgr;
             */
            var field_resMgr        = new CodeFieldReferenceExpression(null, ResMgrFieldName);
            var object_equalsMethod = new CodeMethodReferenceExpression(new CodeTypeReferenceExpression(typeof(Object)), "ReferenceEquals");

            var isResMgrNull = new CodeMethodInvokeExpression(object_equalsMethod, field_resMgr, new CodePrimitiveExpression(null));

            // typeof(<class-name>).Assembly
            var getAssembly = new CodePropertyReferenceExpression(new CodeTypeOfExpression(new CodeTypeReference(srClass.Name)), "Assembly");

            // new ResourceManager(resMgrCtorParam, typeof(<class-name>).Assembly);
            var newResMgr = new CodeObjectCreateExpression(ResMgrCodeTypeReference, new CodePrimitiveExpression(resMgrCtorParam), getAssembly);

            var init = new CodeStatement[2];

            init[0] = new CodeVariableDeclarationStatement(ResMgrCodeTypeReference, tmpVarName, newResMgr);
            init[1] = new CodeAssignStatement(field_resMgr, new CodeVariableReferenceExpression(tmpVarName));

            resMgr.GetStatements.Add(new CodeConditionStatement(isResMgrNull, init));
            resMgr.GetStatements.Add(new CodeMethodReturnStatement(field_resMgr));

            // Add a doc comment to the ResourceManager property
            resMgr.Comments.Add(new CodeCommentStatement(DocCommentSummaryStart, true));
            resMgr.Comments.Add(new CodeCommentStatement(SR.GetString(SR.ResMgrPropertyComment), true));
            resMgr.Comments.Add(new CodeCommentStatement(DocCommentSummaryEnd, true));

            // Emit code for Culture property
            var field_resCulture = new CodeFieldReferenceExpression(null, CultureInfoFieldName);

            culture.GetStatements.Add(new CodeMethodReturnStatement(field_resCulture));

            var newCulture = new CodePropertySetValueReferenceExpression();

            culture.SetStatements.Add(new CodeAssignStatement(field_resCulture, newCulture));

            // Add a doc comment to Culture property
            culture.Comments.Add(new CodeCommentStatement(DocCommentSummaryStart, true));
            culture.Comments.Add(new CodeCommentStatement(SR.GetString(SR.CulturePropertyComment1), true));
            culture.Comments.Add(new CodeCommentStatement(SR.GetString(SR.CulturePropertyComment2), true));
            culture.Comments.Add(new CodeCommentStatement(DocCommentSummaryEnd, true));
        }
        private static bool DefineResourceFetchingProperty(String propertyName, String resourceName, ResourceData data, CodeTypeDeclaration srClass, bool internalClass, bool useStatic)
        {
            var prop = new CodeMemberProperty
            {
                Name   = propertyName,
                HasGet = true,
                HasSet = false
            };

            Type type = data.Type;

            if (type == null)
            {
                return(false);
            }

            if (type == typeof(MemoryStream))
            {
                type = typeof(UnmanagedMemoryStream);
            }

            // Ensure type is internalally visible.  This is necessary to ensure
            // users can access classes via a base type.  Imagine a class like
            // Image or Stream as a internalally available base class, then an
            // internal type like MyBitmap or __UnmanagedMemoryStream as an
            // internal implementation for that base class.  For internalally
            // available strongly typed resource classes, we must return the
            // internal type.  For simplicity, we'll do that for internal strongly
            // typed resource classes as well.  Ideally we'd also like to check
            // for interfaces like IList, but I don't know how to do that without
            // special casing collection interfaces & ignoring serialization
            // interfaces or IDisposable.
            while (!type.IsPublic)
            {
                type = type.BaseType;
            }

            var valueType = new CodeTypeReference(type);

            prop.Type = valueType;
            if (internalClass)
            {
                prop.Attributes = MemberAttributes.Assembly;
            }
            else
            {
                prop.Attributes = MemberAttributes.Public;
            }

            if (useStatic)
            {
                prop.Attributes |= MemberAttributes.Static;
            }

            // For Strings, emit this:
            //    return ResourceManager.GetString("name", _resCulture);
            // For Streams, emit this:
            //    return ResourceManager.GetStream("name", _resCulture);
            // For Objects, emit this:
            //    Object obj = ResourceManager.GetObject("name", _resCulture);
            //    return (MyValueType) obj;
            var resMgr          = new CodePropertyReferenceExpression(null, "ResourceManager");
            var resCultureField = new CodeFieldReferenceExpression((useStatic) ? null : new CodeThisReferenceExpression(), CultureInfoFieldName);

            bool   isString = type == typeof(String);
            bool   isStream = type == typeof(UnmanagedMemoryStream) || type == typeof(MemoryStream);
            String getMethodName;
            String text;
            String valueAsString = TruncateAndFormatCommentStringForOutput(data.ValueAsString);
            String typeName      = String.Empty;

            if (!isString) // Stream or Object
            {
                typeName = TruncateAndFormatCommentStringForOutput(type.ToString());
            }

            if (isString)
            {
                getMethodName = "GetString";
            }
            else if (isStream)
            {
                getMethodName = "GetStream";
            }
            else
            {
                getMethodName = "GetObject";
            }

            if (isString)
            {
                text = SR.GetString(SR.StringPropertyComment, valueAsString);
            }
            else
            {                                               // Stream or Object
                if (valueAsString == null ||
                    String.Equals(typeName, valueAsString)) // If the type did not override ToString, ToString just returns the type name.
                {
                    text = SR.GetString(SR.NonStringPropertyComment, typeName);
                }
                else
                {
                    text = SR.GetString(SR.NonStringPropertyDetailedComment, typeName, valueAsString);
                }
            }

            prop.Comments.Add(new CodeCommentStatement(DocCommentSummaryStart, true));
            prop.Comments.Add(new CodeCommentStatement(text, true));
            prop.Comments.Add(new CodeCommentStatement(DocCommentSummaryEnd, true));

            var getValue = new CodeMethodInvokeExpression(resMgr, getMethodName, new CodePrimitiveExpression(resourceName), resCultureField);
            CodeMethodReturnStatement ret;

            if (isString || isStream)
            {
                ret = new CodeMethodReturnStatement(getValue);
            }
            else
            {
                var returnObj = new CodeVariableDeclarationStatement(typeof(Object), "obj", getValue);
                prop.GetStatements.Add(returnObj);

                ret = new CodeMethodReturnStatement(new CodeCastExpression(valueType, new CodeVariableReferenceExpression("obj")));
            }
            prop.GetStatements.Add(ret);

            srClass.Members.Add(prop);
            return(true);
        }
        private static CodeCompileUnit InternalCreate(Dictionary <String, ResourceData> resourceList, String baseName, String generatedCodeNamespace, String resourcesNamespace, CodeDomProvider codeProvider, bool internalClass, out String[] unmatchable)
        {
            if (baseName == null)
            {
                throw new ArgumentNullException(nameof(baseName));
            }
            if (codeProvider == null)
            {
                throw new ArgumentNullException(nameof(codeProvider));
            }

            // Keep a list of errors describing known strings that couldn't be
            // fixed up (like "4"), as well as listing all duplicate resources that
            // were fixed up to the same name (like "A B" and "A-B" both going to
            // "A_B").
            var errors = new List <string>();

            // Verify the resource names are valid property names, and they don't
            // conflict.  This includes checking for language-specific keywords,
            // translating spaces to underscores, etc.
            SortedList <string, ResourceData> cleanedResourceList = VerifyResourceNames(resourceList, codeProvider, errors, out Dictionary <string, string> reverseFixupTable);

            // Verify the class name is legal.
            String className = baseName;

            // Attempt to fix up class name, and throw an exception if it fails.
            if (!codeProvider.IsValidIdentifier(className))
            {
                String fixedClassName = VerifyResourceName(className, codeProvider);
                if (fixedClassName != null)
                {
                    className = fixedClassName;
                }
            }

            if (!codeProvider.IsValidIdentifier(className))
            {
                throw new ArgumentException(SR.GetString(SR.InvalidIdentifier, className));
            }

            // If we have a namespace, verify the namespace is legal,
            // attempting to fix it up if needed.
            if (!String.IsNullOrEmpty(generatedCodeNamespace))
            {
                if (!codeProvider.IsValidIdentifier(generatedCodeNamespace))
                {
                    String fixedNamespace = VerifyResourceName(generatedCodeNamespace, codeProvider, true);
                    if (fixedNamespace != null)
                    {
                        generatedCodeNamespace = fixedNamespace;
                    }
                }
                // Note we cannot really ensure that the generated code namespace
                // is a valid identifier, as namespaces can have '.' and '::', but
                // identifiers cannot.
            }

            var ccu = new CodeCompileUnit();

            ccu.ReferencedAssemblies.Add("System.dll");

            ccu.UserData.Add("AllowLateBound", false);
            ccu.UserData.Add("RequireVariableDeclaration", true);

            var ns = new CodeNamespace(generatedCodeNamespace);

            ns.Imports.Add(new CodeNamespaceImport("System"));
            ccu.Namespaces.Add(ns);

            // Generate class
            var srClass = new CodeTypeDeclaration(className);

            ns.Types.Add(srClass);
            AddGeneratedCodeAttributeforMember(srClass);

            TypeAttributes ta = internalClass ? TypeAttributes.NotPublic : TypeAttributes.Public;

            //ta |= TypeAttributes.Sealed;
            srClass.TypeAttributes = ta;
            srClass.Comments.Add(new CodeCommentStatement(DocCommentSummaryStart, true));
            srClass.Comments.Add(new CodeCommentStatement(SR.GetString(SR.ClassDocComment), true));

            var comment = new CodeCommentStatement(SR.GetString(SR.ClassComments1), true);

            srClass.Comments.Add(comment);
            comment = new CodeCommentStatement(SR.GetString(SR.ClassComments3), true);
            srClass.Comments.Add(comment);

            srClass.Comments.Add(new CodeCommentStatement(DocCommentSummaryEnd, true));
            var debuggerAttrib =
                new CodeTypeReference(typeof(System.Diagnostics.DebuggerNonUserCodeAttribute))
            {
                Options = CodeTypeReferenceOptions.GlobalReference
            };

            srClass.CustomAttributes.Add(new CodeAttributeDeclaration(debuggerAttrib));

            var compilerGenedAttrib =
                new CodeTypeReference(typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute))
            {
                Options = CodeTypeReferenceOptions.GlobalReference
            };

            srClass.CustomAttributes.Add(new CodeAttributeDeclaration(compilerGenedAttrib));

            // Figure out some basic restrictions to the code generation
            bool useStatic = internalClass || codeProvider.Supports(GeneratorSupport.PublicStaticMembers);

            EmitBasicClassMembers(srClass, generatedCodeNamespace, baseName, resourcesNamespace, internalClass, useStatic);

            // Now for each resource, add a property
            foreach (KeyValuePair <string, ResourceData> entry in cleanedResourceList)
            {
                String propertyName = entry.Key;
                // The resourceName will be the original value, before fixups, if any.
                if (reverseFixupTable.TryGetValue(propertyName, out string resourceName))
                {
                    resourceName = propertyName;
                }
                bool r = DefineResourceFetchingProperty(propertyName, resourceName, entry.Value, srClass, internalClass, useStatic);
                if (!r)
                {
                    errors.Add(propertyName);
                }
            }

            unmatchable = errors.ToArray();

            // Validate the generated class now
            CodeGenerator.ValidateIdentifiers(ccu);

            return(ccu);
        }