StronglyTypedResourceBuilder.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ DotNET / DotNET / 8.0 / untmp / whidbey / REDBITS / ndp / fx / src / Designer / System / Resources / Tools / StronglyTypedResourceBuilder.cs / 2 / StronglyTypedResourceBuilder.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 
/*===========================================================
** 
** Class: StronglyTypedResourceBuilder 
**
** Author: Brian Grunkemeyer ([....]) 
**
** Purpose: Uses CodeDOM to produce a resource class, with a
**          strongly-typed property for every resource.
**          For usability & eventually some perf work. 
**
** Date:  January 16, 2003 
** 
===========================================================*/
 
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic; 
using System.Resources;
using System.CodeDom; 
using System.CodeDom.Compiler; 
using System.Reflection;
using System.Globalization; 
using System.Design;
using System.Xml;
using System.Diagnostics.CodeAnalysis;
 
/*
  Plan for the future: 
  Ideally we will be able to change the property getters here to use a 
  resource index calculated at build time, being the x'th resource in the
  .resources file.  We would then call something like 
  ResourceManager.LookupResourceByIndex().  This would avoid some string
  comparisons during resource lookup.

  This would require work from ResourceReader and/or ResourceWriter (or 
  a standalone, separate utility with duplicated code) to calculate the
  id's.  It would also require that all satellite assemblies use the same 
  resource ID's as the main assembly.  This would require dummy entries 
  for resources in all satellites.
 
  I'm not sure how much time this will save, but it does sound like an
  interesting idea.
         -- Brian Grunkemeyer, 1/16/2003
*/ 

 
#if SYSTEM_WEB  // See DevDiv 9030 
namespace System.PrivateResources.Tools {
#else 
[assembly: SuppressMessage("Microsoft.MSInternal", "CA905:SystemAndMicrosoftNamespacesRequireApproval", Scope="namespace", Target="System.Resources.Tools")]
namespace System.Resources.Tools {
#endif
 
#if SYSTEM_WEB
internal static class StronglyTypedResourceBuilder 
#else 
public static class StronglyTypedResourceBuilder
#endif 
{
    // Note - if you add a new property to the class, add logic to reject
    // keys of that name in VerifyResourceNames.
    private const String ResMgrFieldName = "resourceMan"; 
    private const String ResMgrPropertyName = "ResourceManager";
    private const String CultureInfoFieldName = "resourceCulture"; 
    private const String CultureInfoPropertyName = "Culture"; 

    // When fixing up identifiers, we will replace all these chars with 
    // a single char that is valid in identifiers, such as '_'.
    private static readonly char[] CharsToReplace = new char[] { ' ',
        '\u00A0' /* non-breaking space */, '.', ',', ';', '|', '~', '@',
        '#', '%', '^', '&', '*', '+', '-', '/', '\\', '<', '>', '?', '[', 
        ']', '(', ')', '{', '}', '\"', '\'', ':', '!' };
    private const char ReplacementChar = '_'; 
 
    private const String DocCommentSummaryStart = "";
    private const String DocCommentSummaryEnd = ""; 

    // Maximum size of a String resource to show in the doc comment for its property
    private const int DocCommentLengthThreshold = 512;
 
    // Save the strings for better doc comments.
    internal sealed class ResourceData 
    { 
        private Type _type;
        private String _valueIfString; 

        internal ResourceData(Type type, String valueIfItWasAString)
        {
            _type = type; 
            _valueIfString = valueIfItWasAString;
        } 
 
        internal Type Type {
            get { return _type; } 
        }

        internal String ValueIfString {
            get { return _valueIfString; } 
        }
    } 
 

    ///  
    public static CodeCompileUnit Create(IDictionary resourceList, String baseName, String generatedCodeNamespace, CodeDomProvider codeProvider, bool internalClass, out String[] unmatchable)
    {
        return Create(resourceList, baseName, generatedCodeNamespace, null, codeProvider, internalClass, out unmatchable);
    } 

    ///  
    public static CodeCompileUnit Create(IDictionary resourceList, String baseName, String generatedCodeNamespace, String resourcesNamespace, CodeDomProvider codeProvider, bool internalClass, out String[] unmatchable) 
    {
        if (resourceList == null) 
            throw new ArgumentNullException("resourceList");

        Dictionary resourceTypes = new Dictionary(StringComparer.InvariantCultureIgnoreCase);
        foreach(DictionaryEntry de in resourceList) { 

            ResXDataNode node = de.Value as ResXDataNode; 
            ResourceData data; 
            if (node != null) {
                string keyname = (string) de.Key ; 
                if (keyname != node.Name)
                    throw new ArgumentException(SR.GetString(SR.MismatchedResourceName, keyname, node.Name));

                String typeName = node.GetValueTypeName((AssemblyName[])null); 
                Type type = Type.GetType(typeName);
                String valueAsString = null; 
                if (type == typeof(String)) 
                    valueAsString = (String) node.GetValue((AssemblyName[])null);
                data = new ResourceData(type, valueAsString); 
            }
            else {
                // If the object is null, we don't have a good way of guessing the
                // type.  Use Object.  This will be rare after WinForms gets away 
                // from their resource pull model in Whidbey M3.
                Type type = (de.Value == null) ? typeof(Object) : de.Value.GetType(); 
                data = new ResourceData(type, de.Value as String); 
            }
            resourceTypes.Add((String) de.Key, data); 
        }

        // Note we still need to verify the resource names are valid language
        // keywords, etc.  So there's no point to duplicating the code above. 

        return InternalCreate(resourceTypes, baseName, generatedCodeNamespace, resourcesNamespace, codeProvider, internalClass, out unmatchable); 
    } 

    private static CodeCompileUnit InternalCreate(Dictionary resourceList, String baseName, String generatedCodeNamespace, String resourcesNamespace, CodeDomProvider codeProvider, bool internalClass, out String[] unmatchable) 
    {
        if (baseName == null)
            throw new ArgumentNullException("baseName");
        if (codeProvider == null) 
            throw new ArgumentNullException("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").
        ArrayList errors = new ArrayList(0);

        // 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 cleanedResourceList; 
        Hashtable reverseFixupTable;
        cleanedResourceList = VerifyResourceNames(resourceList, codeProvider, errors, out 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.
        } 
 
        CodeCompileUnit ccu = new CodeCompileUnit();
        ccu.ReferencedAssemblies.Add("System.dll"); 

        ccu.UserData.Add("AllowLateBound", false);
        ccu.UserData.Add("RequireVariableDeclaration", true);
 
        CodeNamespace ns = new CodeNamespace(generatedCodeNamespace);
        ns.Imports.Add(new CodeNamespaceImport("System")); 
        ccu.Namespaces.Add(ns); 

        // Generate class 
        CodeTypeDeclaration 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)); 
        srClass.Comments.Add(new CodeCommentStatement(DocCommentSummaryEnd, true));
        CodeTypeReference debuggerAttrib = new CodeTypeReference(typeof(System.Diagnostics.DebuggerNonUserCodeAttribute));
        debuggerAttrib.Options = CodeTypeReferenceOptions.GlobalReference;
        srClass.CustomAttributes.Add(new CodeAttributeDeclaration(debuggerAttrib)); 

        CodeTypeReference compilerGenedAttrib = new CodeTypeReference(typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute)); 
        compilerGenedAttrib.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);
        bool supportsTryCatch = codeProvider.Supports(GeneratorSupport.TryCatchStatements);
        EmitBasicClassMembers(srClass, generatedCodeNamespace, baseName, resourcesNamespace, internalClass, useStatic, supportsTryCatch); 

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

        unmatchable = (String[]) errors.ToArray(typeof(String));

        // Validate the generated class now 
        CodeGenerator.ValidateIdentifiers(ccu);
 
        return ccu; 
    }
 
    public static CodeCompileUnit Create(String resxFile, String baseName, String generatedCodeNamespace, CodeDomProvider codeProvider, bool internalClass, out String[] unmatchable)
    {
        return Create(resxFile, baseName, generatedCodeNamespace, null, codeProvider, internalClass, out unmatchable);
    } 

    [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly")] 
    public static CodeCompileUnit Create(String resxFile, String baseName, String generatedCodeNamespace, String resourcesNamespace, CodeDomProvider codeProvider, bool internalClass, out String[] unmatchable) 
    {
        if (resxFile == null) 
            throw new ArgumentNullException("resxFile");

        // Read the resources from a ResX file into a dictionary - name & type name
        Dictionary resourceList = new Dictionary(StringComparer.InvariantCultureIgnoreCase); 
        using(ResXResourceReader rr = new ResXResourceReader(resxFile)) {
            rr.UseResXDataNodes = true; 
            foreach(DictionaryEntry de in rr) { 
                ResXDataNode node = (ResXDataNode) de.Value;
                String typeName = node.GetValueTypeName((AssemblyName[])null); 
                Type type = Type.GetType(typeName);
                String valueAsString = null;
                if (type == typeof(String))
                    valueAsString = (String) node.GetValue((AssemblyName[])null); 
                ResourceData data = new ResourceData(type, valueAsString);
                resourceList.Add((String) de.Key, data); 
            } 
        }
 
        // Note we still need to verify the resource names are valid language
        // keywords, etc.  So there's no point to duplicating the code above.

        return InternalCreate(resourceList, baseName, generatedCodeNamespace, resourcesNamespace, codeProvider, internalClass, out unmatchable); 
    }
 
    private static void AddGeneratedCodeAttributeforMember(CodeTypeMember typeMember) { 
        CodeAttributeDeclaration generatedCodeAttrib = new CodeAttributeDeclaration(new CodeTypeReference(typeof(System.CodeDom.Compiler.GeneratedCodeAttribute)));
        generatedCodeAttrib.AttributeType.Options = CodeTypeReferenceOptions.GlobalReference; 
        CodeAttributeArgument toolArg = new CodeAttributeArgument(new CodePrimitiveExpression(typeof(StronglyTypedResourceBuilder).FullName));
        CodeAttributeArgument versionArg = new CodeAttributeArgument(new CodePrimitiveExpression(ThisAssembly.Version));

        generatedCodeAttrib.Arguments.Add(toolArg); 
        generatedCodeAttrib.Arguments.Add(versionArg);
 
        typeMember.CustomAttributes.Add(generatedCodeAttrib); 
    }
 
    [SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters")]
    private static void EmitBasicClassMembers(CodeTypeDeclaration srClass, String nameSpace, String baseName, String resourcesNamespace, bool internalClass, bool useStatic, bool supportsTryCatch)
    {
        const String tmpVarName = "temp"; 
        String resMgrCtorParam;
 
        if (resourcesNamespace != null) { 
            if (resourcesNamespace.Length > 0)
                resMgrCtorParam = resourcesNamespace + '.' + baseName; 
            else
                resMgrCtorParam = baseName;
        }
        else if ((nameSpace != null) && (nameSpace.Length > 0)) { 
            resMgrCtorParam = nameSpace + '.' + baseName;
        } 
        else { 
            resMgrCtorParam = baseName;
        } 

        // Emit a comment on the class
        CodeCommentStatement comment = new CodeCommentStatement(SR.GetString(SR.ClassComments1));
        srClass.Comments.Add(comment); 
        comment = new CodeCommentStatement(SR.GetString(SR.ClassComments2));
        srClass.Comments.Add(comment); 
        comment = new CodeCommentStatement(SR.GetString(SR.ClassComments3)); 
        srClass.Comments.Add(comment);
        comment = new CodeCommentStatement(SR.GetString(SR.ClassComments4)); 
        srClass.Comments.Add(comment);

        CodeAttributeDeclaration suppressMessageAttrib = new CodeAttributeDeclaration(new CodeTypeReference(typeof(System.Diagnostics.CodeAnalysis.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 (VSWhidbey 251554)
        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.
        CodeTypeReference ResMgrCodeTypeReference = new CodeTypeReference(typeof(ResourceManager), CodeTypeReferenceOptions.GlobalReference); 
        CodeMemberField field = new CodeMemberField(ResMgrCodeTypeReference, ResMgrFieldName);
        field.Attributes = MemberAttributes.Private;
        if (useStatic)
            field.Attributes |= MemberAttributes.Static; 
        srClass.Members.Add(field);
 
        // Emit _resCulture field, and leave it set to null. 
        CodeTypeReference 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
        CodeTypeReference editorBrowsableStateTypeRef = new CodeTypeReference(typeof(System.ComponentModel.EditorBrowsableState));
        editorBrowsableStateTypeRef.Options = CodeTypeReferenceOptions.GlobalReference; 

        CodeAttributeArgument editorBrowsableStateAdvanced = new CodeAttributeArgument(new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(editorBrowsableStateTypeRef), "Advanced")); 
        CodeAttributeDeclaration editorBrowsableAdvancedAttribute = new CodeAttributeDeclaration("System.ComponentModel.EditorBrowsableAttribute", 
                                                                                                 new CodeAttributeArgument[] {editorBrowsableStateAdvanced});
        editorBrowsableAdvancedAttribute.AttributeType.Options = CodeTypeReferenceOptions.GlobalReference; 
        resMgr.CustomAttributes.Add(editorBrowsableAdvancedAttribute);

        // Emit the Culture property (read/write)
        CodeMemberProperty 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, we should use it here.
          if (_resMgr == null) { 
              ResourceManager tmp = new ResourceManager("", typeof("").Assembly);
              _resMgr = tmp; 
          } 
          return _resMgr;
         */ 
        CodeFieldReferenceExpression field_resMgr = new CodeFieldReferenceExpression(null, ResMgrFieldName);
        CodeMethodReferenceExpression object_equalsMethod = new CodeMethodReferenceExpression(new CodeTypeReferenceExpression(typeof(Object)), "ReferenceEquals");

        CodeMethodInvokeExpression isResMgrNull = new CodeMethodInvokeExpression(object_equalsMethod, new CodeExpression[] { field_resMgr, new CodePrimitiveExpression(null)}); 

        // typeof().Assembly 
        CodePropertyReferenceExpression getAssembly = new CodePropertyReferenceExpression(new CodeTypeOfExpression(new CodeTypeReference(srClass.Name)), "Assembly"); 

        // new ResourceManager(resMgrCtorParam, typeof().Assembly); 
        CodeObjectCreateExpression newResMgr = new CodeObjectCreateExpression(ResMgrCodeTypeReference, new CodePrimitiveExpression(resMgrCtorParam), getAssembly);

        CodeStatement[] 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 
        CodeFieldReferenceExpression field_resCulture = new CodeFieldReferenceExpression(null, CultureInfoFieldName);
        culture.GetStatements.Add(new CodeMethodReturnStatement(field_resCulture)); 

        CodePropertySetValueReferenceExpression 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)); 
    }


    // Defines a property like this: 
    // {public|internal} {static} Point MyPoint {
    //     get { 
    //          Object obj = ResourceManager.GetObject("MyPoint", _resCulture); 
    //          return (Point) obj; }
    // } 
    // Special cases static vs. non-static, as well as public vs. internal.
    // Also note the resource name could contain spaces, etc, while the
    // property name has to be a valid language identifier.
    [SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters")] 
    private static bool DefineResourceFetchingProperty(String propertyName, String resourceName, ResourceData data, CodeTypeDeclaration srClass, bool internalClass, bool useStatic)
    { 
        CodeMemberProperty prop = new CodeMemberProperty(); 
        prop.Name = propertyName;
        prop.HasGet = true; 
        prop.HasSet = false;

        Type type = data.Type;
 
        if (type == null) {
            return false; 
        } 

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

        // Ensure type is publically visible.  This is necessary to ensure
        // users can access classes via a base type.  Imagine a class like 
        // Image or Stream as a publically available base class, then an
        // internal type like MyBitmap or __UnmanagedMemoryStream as an 
        // internal implementation for that base class.  For publically 
        // available strongly typed resource classes, we must return the
        // public 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; 
 
        CodeTypeReference 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; 
        CodePropertyReferenceExpression resMgr = new CodePropertyReferenceExpression(null, "ResourceManager"); 
        CodeFieldReferenceExpression resCultureField = new CodeFieldReferenceExpression((useStatic) ? null : new CodeThisReferenceExpression(), CultureInfoFieldName);
 
        bool isString = type == typeof(String);
        bool isStream = type == typeof(UnmanagedMemoryStream) || type == typeof(MemoryStream);
        String getMethodName = "GetObject";
        if (isString) { 
            getMethodName = "GetString";
            String docValue = data.ValueIfString; 
            if (docValue == null) 
                docValue = String.Empty;
 
            // Stop at some length
            if (docValue.Length > DocCommentLengthThreshold)
                docValue = SR.GetString(SR.StringPropertyTruncatedComment, docValue.Substring(0, DocCommentLengthThreshold));
 
            // Encode the comment so it is safe for xml.  SecurityElement.Escape is the only method I've found to do this.
            docValue = System.Security.SecurityElement.Escape(docValue); 
 
            String text = String.Format(CultureInfo.CurrentCulture, SR.GetString(SR.StringPropertyComment), docValue);
            prop.Comments.Add(new CodeCommentStatement(DocCommentSummaryStart, true)); 
            prop.Comments.Add(new CodeCommentStatement(text, true));
            prop.Comments.Add(new CodeCommentStatement(DocCommentSummaryEnd, true));
        }
        else if (isStream) 
            getMethodName = "GetStream";
 
        CodeExpression getValue = new CodeMethodInvokeExpression(resMgr, getMethodName, new CodePrimitiveExpression(resourceName), resCultureField); 
        CodeMethodReturnStatement ret;
        if (isString || isStream) { 
            ret = new CodeMethodReturnStatement(getValue);
        }
        else {
            CodeVariableDeclarationStatement 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;
    } 

    // Returns a valid identifier made from key, or null if it can't. 
    public static String VerifyResourceName(String key, CodeDomProvider provider) 
    {
        return VerifyResourceName(key, provider, false); 
    }

    // Once CodeDom provides a way to verify a namespace name, revisit this method.
    private static String VerifyResourceName(String key, CodeDomProvider provider, bool isNameSpace) { 
        if (key == null)
            throw new ArgumentNullException("key"); 
        if (provider == null) 
            throw new ArgumentNullException("provider");
 
        foreach(char c in CharsToReplace) {
            // For namespaces, allow . and ::
            if (!(isNameSpace && (c == '.' || c == ':')))
                key = key.Replace(c, ReplacementChar); 
        }
 
        if (provider.IsValidIdentifier(key)) 
            return key;
 
        // Now try fixing up keywords like "for".
        key = provider.CreateValidIdentifier(key);
        if (provider.IsValidIdentifier(key))
            return key; 

        // make one last ditch effort by prepending _.  This fixes keys that start with a number 
        key = "_" + key; 
        if (provider.IsValidIdentifier(key))
            return key; 

        return null;
    }
 
    private static SortedList VerifyResourceNames(Dictionary resourceList, CodeDomProvider codeProvider, ArrayList errors, out Hashtable reverseFixupTable)
    { 
        reverseFixupTable = new Hashtable(0, StringComparer.InvariantCultureIgnoreCase); 
        SortedList cleanedResourceList = new SortedList(StringComparer.InvariantCultureIgnoreCase, resourceList.Count);
 
        foreach(KeyValuePair entry in resourceList) {
            String key = entry.Key;

            // Disallow a property named ResourceManager or Culture - we add 
            // those.  (Any other properties we add also must be listed here)
            // Also disallow resource values of type Void. 
            if (String.Equals(key, ResMgrPropertyName) || 
                String.Equals(key, CultureInfoPropertyName) ||
                typeof(void) == entry.Value.Type) 
            {
                errors.Add(key);
                continue;
            } 

            // Ignore WinForms design time and hierarchy information. 
            // Skip resources starting with $ or >>, like "$this.Text", 
            // ">>$this.Name" or ">>treeView1.Parent".
            if ((key.Length > 0 && key[0] == '$') || 
                (key.Length > 1 && key[0] == '>' && key[1] == '>')) {
                continue;
            }
 

            if (!codeProvider.IsValidIdentifier(key)) { 
                String newKey = VerifyResourceName(key, codeProvider, false); 
                if (newKey == null) {
                    errors.Add(key); 
                    continue;
                }

                // Now see if we've already mapped another key to the 
                // same name.
                String oldDuplicateKey = (String) reverseFixupTable[newKey]; 
                if (oldDuplicateKey != null) { 
                    // We can't handle this key nor the previous one.
                    // Remove the old one. 
                    if (!errors.Contains(oldDuplicateKey))
                        errors.Add(oldDuplicateKey);
                    if (cleanedResourceList.Contains(newKey))
                        cleanedResourceList.Remove(newKey); 
                    errors.Add(key);
                    continue; 
                } 
                reverseFixupTable[newKey] = key;
                key = newKey; 
            }
            ResourceData value = entry.Value;
            if (!cleanedResourceList.Contains(key))
                cleanedResourceList.Add(key, value); 
            else {
                // There was a case-insensitive conflict between two keys. 
                // Or possibly one key was fixed up in a way that conflicts 
                // with another key (ie, "A B" and "A_B").
                String fixedUp = (String) reverseFixupTable[key]; 
                if (fixedUp != null) {
                    if (!errors.Contains(fixedUp))
                        errors.Add(fixedUp);
                    reverseFixupTable.Remove(key); 
                }
                errors.Add(entry.Key); 
                cleanedResourceList.Remove(key); 
            }
        } 
        return cleanedResourceList;
    }

} 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.


                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK