Esempio n. 1
0
        /// <summary>
        /// Creates a new <see cref="CodeTypeDeclaration"/> that is the generated form of
        /// the given <paramref name="enumType"/>.
        /// </summary>
        /// <param name="enumType">The enum type to generate.</param>
        /// <param name="codeGenerator">The current proxy generator context.</param>
        /// <returns>The newly generated enum type declaration.</returns>
        internal static CodeTypeDeclaration CreateEnumTypeDeclaration(Type enumType, CodeDomClientCodeGenerator codeGenerator)
        {
            System.Diagnostics.Debug.Assert(enumType.IsEnum, "Type must be an enum type");

            CodeTypeDeclaration typeDecl = CodeGenUtilities.CreateTypeDeclaration(enumType);

            typeDecl.IsEnum = true;

            // Always force generated enums to be public
            typeDecl.TypeAttributes |= TypeAttributes.Public;

            // Enums deriving from anything but int get an explicit base type
            Type underlyingType = enumType.GetEnumUnderlyingType();

            if (underlyingType != typeof(int))
            {
                typeDecl.BaseTypes.Add(new CodeTypeReference(underlyingType));
            }

            typeDecl.Comments.AddRange(CodeGenUtilities.GenerateSummaryCodeComment($"Enum {enumType.Name}", codeGenerator.IsCSharp));

            // Generate [DataContract] if it appears in the original only.  Use Reflection only because that matches
            // what WCF will do.
            DataContractAttribute dataContractAttr = (DataContractAttribute)Attribute.GetCustomAttribute(enumType, typeof(DataContractAttribute));

            if (dataContractAttr != null)
            {
                CodeAttributeDeclaration attrDecl = CodeGenUtilities.CreateDataContractAttributeDeclaration(enumType, codeGenerator, typeDecl);
                typeDecl.CustomAttributes.Add(attrDecl);
            }

            string[] memberNames   = Enum.GetNames(enumType);
            Type     enumValueType = Enum.GetUnderlyingType(enumType);

            for (int i = 0; i < memberNames.Length; ++i)
            {
                string            memberName  = memberNames[i];
                CodeTypeReference enumTypeRef = CodeGenUtilities.GetTypeReference(enumValueType, codeGenerator, typeDecl);
                CodeMemberField   enumMember  = new CodeMemberField(enumTypeRef, memberName);

                enumMember.Comments.AddRange(CodeGenUtilities.GenerateSummaryCodeComment(memberName, codeGenerator.IsCSharp));

                // Generate an initializer for the enum member.
                // GetRawConstantValue is the safest way to get the raw value of the enum field
                // and works for both Reflection and ReflectionOnly loaded assemblies.
                FieldInfo fieldInfo = enumType.GetField(memberName);
                if (fieldInfo != null)
                {
                    object memberValue = fieldInfo.GetRawConstantValue();

                    Debug.Assert(memberValue != null, "Enum type's GetRawConstantValue should never return null");

                    // We special-case MinValue and MaxValue for the integral types
                    // because VisualBasic will generate overflow compiler error for
                    // Int64.MinValue.   If we detect a known MinValue or MaxValue for
                    // this integral type, we generate that reference, otherwise we
                    // just generate a constant integral value of the enum's type
                    object[] minMaxValues = null;
                    CodeGenUtilities.integralMinMaxValues.TryGetValue(underlyingType, out minMaxValues);
                    Debug.Assert(minMaxValues == null || minMaxValues.Length == 3, "integralMinMaxValues elements must always contain 3 values");

                    // Gen xxx.MinValue if it matches, but give precedence to matching a true zero,
                    // which is the min value for the unsigned integral types
                    // minMaxValues[0]: the MinValue for this type
                    // minMaxValues[1]: the MaxValue for this type
                    // minMaxValues[2]: the zero for this type (memberValue is not boxed and cannot be cast)
                    if (minMaxValues != null && !memberValue.Equals(minMaxValues[2]) && memberValue.Equals(minMaxValues[0]))
                    {
                        enumMember.InitExpression = new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(underlyingType), "MinValue");
                    }
                    // Gen xxx.MaxValue if it matches
                    else if (minMaxValues != null && memberValue.Equals(minMaxValues[1]))
                    {
                        enumMember.InitExpression = new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(underlyingType), "MaxValue");
                    }
                    // All other cases generate an integral constant.
                    // CodeDom knows how to generate the right integral constant based on memberValue's type.
                    else
                    {
                        enumMember.InitExpression = new CodePrimitiveExpression(memberValue);
                    }
                }

                typeDecl.Members.Add(enumMember);

                // Generate an [EnumMember] if appropriate
                EnumMemberAttribute enumMemberAttr = (EnumMemberAttribute)Attribute.GetCustomAttribute(fieldInfo, typeof(EnumMemberAttribute));
                if (enumMemberAttr != null)
                {
                    CodeAttributeDeclaration enumAttrDecl = CodeGenUtilities.CreateEnumMemberAttributeDeclaration(fieldInfo, codeGenerator, typeDecl);
                    enumMember.CustomAttributes.Add(enumAttrDecl);
                }

                // Propagate any other attributes that can be seen by the client
                CustomAttributeGenerator.GenerateCustomAttributes(
                    codeGenerator,
                    typeDecl,
                    ex => string.Format(CultureInfo.CurrentCulture, Resource.ClientCodeGen_Attribute_ThrewException_CodeTypeMember, ex.Message, fieldInfo.Name, typeDecl.Name, ex.InnerException.Message),
                    fieldInfo.GetCustomAttributes(false).Cast <Attribute>().Where(a => a.GetType() != typeof(EnumMemberAttribute)),
                    enumMember.CustomAttributes,
                    enumMember.Comments);
            }

            // Attributes marked with [Flag] propagate it
            if (enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Length > 0)
            {
                CodeAttributeDeclaration attrDecl = CodeGenUtilities.CreateAttributeDeclaration(typeof(FlagsAttribute), codeGenerator, typeDecl);
                typeDecl.CustomAttributes.Add(attrDecl);
            }
            return(typeDecl);
        }