Ejemplo n.º 1
0
        /// <summary>
        /// Gets a <see cref="CodeTypeReference"/> for a CLR type.
        /// </summary>
        /// <param name="type">A CLR type.</param>
        /// <param name="codeGenerator">A <see cref="CodeDomClientCodeGenerator"/>.</param>
        /// <param name="referencingType">The referencing type.</param>
        /// <param name="optimizeAttributeName">Indicates whether or not to optimize <see cref="Attribute"/> names by removing the "Attribute" suffix.</param>
        /// <param name="forceUseFullyQualifiedName">Indicates whether or not to generate the type using the fully qualified name irrespective the global setting.</param>
        /// <returns>A <see cref="CodeTypeReference"/> for a CLR type.</returns>
        internal static CodeTypeReference GetTypeReference(Type type, CodeDomClientCodeGenerator codeGenerator, CodeTypeDeclaration referencingType, bool optimizeAttributeName, bool forceUseFullyQualifiedName)
        {
            string typeName      = type.Name;
            string typeNamespace = type.Namespace;

            // Add an import statement to the referencing type if needed
            CodeNamespace     ns = codeGenerator.GetNamespace(referencingType);
            CodeTypeReference codeTypeReference = null;

            // Attribute?  If so, we special case these and remove the 'Attribute' suffix if present.
            if (optimizeAttributeName)
            {
                typeName = OptimizeAttributeName(type);
            }

            // Determine if we should generate this type with a full type name
            bool useFullyQualifiedName = forceUseFullyQualifiedName || CodeGenUtilities._useFullTypeNames || RegisterTypeName(typeNamespace, typeName, ns.Name);

            // Make sure we take into account root namespace in VB codegen.
            typeNamespace = TranslateNamespace(type, codeGenerator);

            // Conditionally add an import statement.  Skip this step if we need to generate a full
            // type name, if we're already in the target namespace, or if the type is in the global namespace.
            if (!useFullyQualifiedName && !ns.Name.Equals(type.Namespace) && !string.IsNullOrEmpty(type.Namespace))
            {
                // If the namespace is already imported, the following line will be a no-op.
                ns.Imports.Add(new CodeNamespaceImport(typeNamespace));
            }

            // If forced using Fully Qualified names, dont look up or store the code reference in the cache. That is because,
            // we force the use of fully qualified names only in certain cases. Caching at this time will cause the fully qualified name
            // to be used every time.
            bool useCache = !forceUseFullyQualifiedName;

            // See if we already have a reference for this type
            Tuple <CodeNamespace, Type> tupleKey = new Tuple <CodeNamespace, Type>(ns, type);

            if (!useCache || !CodeGenUtilities._codeTypeReferences.TryGetValue(tupleKey, out codeTypeReference))
            {
                if (useFullyQualifiedName && !string.IsNullOrEmpty(typeNamespace))
                {
                    // While this splicing may seem awkward, we perform this task
                    // rather than rely on 'type.FullName' as we may have performed
                    // a VB root namespace translation task above.
                    typeName = typeNamespace + "." + typeName;
                }

                // If not, create a new type reference. Use the constructor for CodeTypeReference
                // that takes a type's name rather than type to generate short names.
                if (type.IsArray)
                {
                    codeTypeReference = new CodeTypeReference(
                        CodeGenUtilities.GetTypeReference(type.GetElementType(), codeGenerator, referencingType, /* optimizeAttributeName */ false, forceUseFullyQualifiedName),
                        type.GetArrayRank());
                }
                else if (type.IsGenericType)
                {
                    Type[] genericArguments           = type.GetGenericArguments();
                    CodeTypeReference[] typeArguments = new CodeTypeReference[genericArguments.Length];
                    for (int i = 0; i < genericArguments.Length; i++)
                    {
                        typeArguments[i] = GetTypeReference(genericArguments[i], codeGenerator, referencingType);
                    }
                    codeTypeReference = new CodeTypeReference(typeName, typeArguments);
                }
                else
                {
                    // Generate language-specific shorthands for core types by using CodeTypeReference constructor that takes a Type
                    if (type.IsPrimitive || type == typeof(void) || type == typeof(decimal) || type == typeof(string) || type == typeof(object))
                    {
                        codeTypeReference = new CodeTypeReference(type);
                    }
                    else
                    {
                        codeTypeReference = new CodeTypeReference(typeName);
                    }
                }

                // Keep track of the CLR type for identification purposes.
                codeTypeReference.UserData["ClrType"] = type;

                // Cache for later use.
                if (useCache)
                {
                    CodeGenUtilities._codeTypeReferences.Add(tupleKey, codeTypeReference);
                }
            }

            return(codeTypeReference);
        }