/// <summary>
        /// Generates a custom method.
        /// </summary>
        /// <param name="domainMethod">The custom method to be generated.</param>
        protected virtual void GenerateCustomMethod(DomainOperationEntry domainMethod)
        {
            this.Write("public void ");

            this.Write(this.ToStringHelper.ToStringWithCulture(domainMethod.Name));

            this.Write("(");


            List <string> invokeParams = new List <string>();

            DomainOperationParameter[] paramInfos = domainMethod.Parameters.ToArray();
            for (int i = 0; i < paramInfos.Length; i++)
            {
                DomainOperationParameter paramInfo = paramInfos[i];
                string paramTypeName = CodeGenUtilities.GetTypeName(CodeGenUtilities.TranslateType(paramInfo.ParameterType));

                this.Write(this.ToStringHelper.ToStringWithCulture(paramTypeName));

                this.Write(" ");

                this.Write(this.ToStringHelper.ToStringWithCulture(CodeGenUtilities.GetSafeName(paramInfo.Name)));


                if (i + 1 < paramInfos.Length)
                {
                    this.Write(", ");
                }
                if (i > 0)
                {
                    invokeParams.Add(paramInfo.Name);
                }
            }

            this.Write(")\r\n");


            this.GenerateOpeningBrace();

            this.Write(this.ToStringHelper.ToStringWithCulture(paramInfos[0].Name));

            this.Write(".");

            this.Write(this.ToStringHelper.ToStringWithCulture(domainMethod.Name));

            this.Write("(");


            for (int i = 0; i < invokeParams.Count; i++)
            {
                this.Write(this.ToStringHelper.ToStringWithCulture(invokeParams[i]));


                if (i + 1 < invokeParams.Count)
                {
                    this.Write(", ");
                }
            }

            this.Write(");\r\n");


            this.GenerateClosingBrace();
        }
        private string GetEntityQueryMethodElementReturnTypeName(DomainOperationEntry domainOperationEntry)
        {
            Type entityType = TypeUtility.GetElementType(domainOperationEntry.ReturnType);

            return(CodeGenUtilities.GetTypeName(entityType));
        }
        /// <summary>
        /// Generates attribute declarations in C#.
        /// </summary>
        /// <param name="attributes">The attributes to be generated.</param>
        /// <param name="forcePropagation">Causes the attributes to be generated even if the attribute verification fails.</param>
        protected virtual void GenerateAttributes(IEnumerable <Attribute> attributes, bool forcePropagation)
        {
            foreach (Attribute attribute in attributes.OrderBy(a => a.GetType().Name))
            {
                AttributeDeclaration attributeDeclaration = AttributeGeneratorHelper.GetAttributeDeclaration(attribute, this.ClientCodeGenerator, forcePropagation);
                if (attributeDeclaration == null || attributeDeclaration.HasErrors)
                {
                    continue;
                }

                string attributeTypeName = CodeGenUtilities.GetTypeName(attributeDeclaration.AttributeType);

                this.Write("[");

                this.Write(this.ToStringHelper.ToStringWithCulture(attributeTypeName));

                this.Write("(");


                if (attributeDeclaration.ConstructorArguments.Count > 0)
                {
                    for (int i = 0; i < attributeDeclaration.ConstructorArguments.Count; i++)
                    {
                        object value       = attributeDeclaration.ConstructorArguments[i];
                        string stringValue = AttributeGeneratorHelper.ConvertValueToCode(value, true);

                        this.Write(this.ToStringHelper.ToStringWithCulture(stringValue));


                        if (i + 1 < attributeDeclaration.ConstructorArguments.Count)
                        {
                            this.Write(", ");
                        }
                    }
                }
                if (attributeDeclaration.NamedParameters.Count > 0)
                {
                    if (attributeDeclaration.ConstructorArguments.Count > 0)
                    {
                        this.Write(", ");
                    }

                    for (int i = 0; i < attributeDeclaration.NamedParameters.Count; i++)
                    {
                        KeyValuePair <string, object> pair = attributeDeclaration.NamedParameters.ElementAt(i);
                        string stringValue = AttributeGeneratorHelper.ConvertValueToCode(pair.Value, true);

                        this.Write(this.ToStringHelper.ToStringWithCulture(pair.Key));

                        this.Write("=");

                        this.Write(this.ToStringHelper.ToStringWithCulture(stringValue));


                        if (i + 1 < attributeDeclaration.NamedParameters.Count)
                        {
                            this.Write(",");
                        }
                    }
                }

                this.Write(")]\r\n");
            }
        }
        private void GenerateEnumMembers(Type enumType)
        {
            Type underlyingType = enumType.GetEnumUnderlyingType();

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

            for (int i = 0; i < memberNames.Length; ++i)
            {
                string    memberName = memberNames[i];
                FieldInfo fieldInfo  = enumType.GetField(memberName);

                this.GenerateEnumMemberAttributes(fieldInfo);

                if (fieldInfo != null)
                {
                    object memberValue = fieldInfo.GetRawConstantValue();

                    object[] minMaxValues = null;
                    CodeGenUtilities.IntegralMinMaxValues.TryGetValue(underlyingType, out minMaxValues);

                    if (minMaxValues != null && !memberValue.Equals(minMaxValues[2]) && memberValue.Equals(minMaxValues[0]))
                    {
                        this.Write(this.ToStringHelper.ToStringWithCulture(memberName));

                        this.Write(" = ");

                        this.Write(this.ToStringHelper.ToStringWithCulture(CodeGenUtilities.GetTypeName(underlyingType)));

                        this.Write(".MinValue ");
                    }
                    else if (minMaxValues != null && memberValue.Equals(minMaxValues[1]))
                    {
                        this.Write(" \r\n");

                        this.Write(this.ToStringHelper.ToStringWithCulture(memberName));

                        this.Write(" = ");

                        this.Write(this.ToStringHelper.ToStringWithCulture(CodeGenUtilities.GetTypeName(underlyingType)));

                        this.Write(".MaxValue ");
                    }
                    else
                    {
                        this.Write(" \r\n");

                        this.Write(this.ToStringHelper.ToStringWithCulture(memberName));

                        this.Write(" = ");

                        this.Write(this.ToStringHelper.ToStringWithCulture(memberValue.ToString()));

                        this.Write(" ");
                    }

                    if (i + 1 < memberNames.Length)
                    {
                        this.Write(",");
                    }
                }
            }
        }
        /// <summary>
        /// Generates the client proxy code for the given type.
        /// </summary>
        public override void Generate()
        {
            // ----------------------------------------------------------------
            // namespace
            // ----------------------------------------------------------------
            var ns = ClientProxyGenerator.GetOrGenNamespace(Type);

            // Missing namespace bails out of code-gen -- error has been logged
            if (ns == null)
            {
                return;
            }

            // ----------------------------------------------------------------
            // public partial class {Type} : (Base)
            // ----------------------------------------------------------------
            ProxyClass                = CodeGenUtilities.CreateTypeDeclaration(Type);
            ProxyClass.IsPartial      = true; // makes this a partial type
            ProxyClass.TypeAttributes = TypeAttributes.Public;

            // Abstract classes must be preserved as abstract to avoid explicit instantiation on client
            bool isAbstract = (Type.IsAbstract);

            if (isAbstract)
            {
                ProxyClass.TypeAttributes |= TypeAttributes.Abstract;
            }

            // Determine all types derived from this one.
            // Note this list does not assume the current type is the visible root.  That is a separate test.
            IEnumerable <Type> derivedTypes = GetDerivedTypes();

            // If this type doesn't have any derivatives, seal it.  Cannot seal abstracts.
            if (!isAbstract && !derivedTypes.Any())
            {
                ProxyClass.TypeAttributes |= TypeAttributes.Sealed;
            }

            // Add all base types including interfaces
            AddBaseTypes(ns);
            ns.Types.Add(ProxyClass);

            AttributeCollection typeAttributes = Type.Attributes();

            // Add <summary> xml comment to class
            string comment = GetSummaryComment();

            ProxyClass.Comments.AddRange(CodeGenUtilities.GenerateSummaryCodeComment(comment, ClientProxyGenerator.IsCSharp));

            // ----------------------------------------------------------------
            // Add default ctr
            // ----------------------------------------------------------------
            CodeConstructor constructor = new CodeConstructor();

            // Default ctor is public for concrete types but protected for abstracts.
            // This prevents direct instantiation on client
            constructor.Attributes = isAbstract ? MemberAttributes.Family : MemberAttributes.Public;

            // add default ctor doc comments
            comment = string.Format(CultureInfo.CurrentCulture, Resource.CodeGen_Default_Constructor_Summary_Comments, Type.Name);
            constructor.Comments.AddRange(CodeGenUtilities.GenerateSummaryCodeComment(comment, ClientProxyGenerator.IsCSharp));

            // add call to default OnCreated method
            constructor.Statements.Add(NotificationMethodGen.OnCreatedMethodInvokeExpression);
            ProxyClass.Members.Add(constructor);

            // ----------------------------------------------------------------
            // [KnownType(...), ...]
            // ----------------------------------------------------------------

            // We need to generate a [KnownType] for all derived entities on the visible root.
            if (!IsDerivedType)
            {
                // Generate a [KnownType] for every derived type.
                // We specifically exclude [KnownTypes] from the set of attributes we ask
                // the metadata pipeline to generate below, meaning we take total control
                // here for which [KnownType] attributes get through the metadata pipeline.
                //
                // Note, we sort in alphabetic order to give predictability in baselines and
                // client readability.  For cosmetic reasons, we sort by short or long name
                // depending on what our utility helpers will actually generated
                foreach (Type derivedType in derivedTypes.OrderBy(t => ClientProxyGenerator.ClientProxyCodeGenerationOptions.UseFullTypeNames ? t.FullName : t.Name))
                {
                    CodeAttributeDeclaration knownTypeAttrib = CodeGenUtilities.CreateAttributeDeclaration(typeof(System.Runtime.Serialization.KnownTypeAttribute), ClientProxyGenerator, ProxyClass);
                    knownTypeAttrib.Arguments.Add(new CodeAttributeArgument(new CodeTypeOfExpression(CodeGenUtilities.GetTypeReference(derivedType, ClientProxyGenerator, ProxyClass))));
                    ProxyClass.CustomAttributes.Add(knownTypeAttrib);
                }
            }

            ValidateTypeAttributes(typeAttributes);

            // ----------------------------------------------------------------
            // [DataContract(Namespace=X, Name=Y)]
            // ----------------------------------------------------------------
            CodeAttributeDeclaration dataContractAttrib = CodeGenUtilities.CreateDataContractAttributeDeclaration(Type, ClientProxyGenerator, ProxyClass);

            ProxyClass.CustomAttributes.Add(dataContractAttrib);

            // ----------------------------------------------------------------
            // Propagate all type-level Attributes across (except DataContractAttribute since that is handled above)
            // -----------------------------------------------------------------
            CustomAttributeGenerator.GenerateCustomAttributes(
                ClientProxyGenerator,
                ProxyClass,
                ex => string.Format(CultureInfo.CurrentCulture, Resource.ClientCodeGen_Attribute_ThrewException_CodeType, ex.Message, ProxyClass.Name, ex.InnerException.Message),
                FilterTypeAttributes(typeAttributes),
                ProxyClass.CustomAttributes,
                ProxyClass.Comments);

            // ----------------------------------------------------------------
            // gen proxy getter/setter for each property
            // ----------------------------------------------------------------
            GenerateProperties();

            // ----------------------------------------------------------------
            // gen additional methods/events
            // ----------------------------------------------------------------
            GenerateAdditionalMembers();

            // Register created CodeTypeDeclaration with mapping
            _typeMapping[Type] = ProxyClass;
        }
        /// <summary>
        /// Generates all of the properties for the type.
        /// </summary>
        private void GenerateProperties()
        {
            IEnumerable <PropertyDescriptor> properties = TypeDescriptor.GetProperties(Type)
                                                          .Cast <PropertyDescriptor>()
                                                          .OrderBy(p => p.Name);

            foreach (PropertyDescriptor pd in properties)
            {
                if (!ShouldDeclareProperty(pd))
                {
                    continue;
                }

                // Generate a property getter/setter pair for every property whose type
                // we support. Non supported property types will be skipped.
                if (CanGenerateProperty(pd))
                {
                    // Ensure the property is not virtual, abstract or new
                    // If there is a violation, we log the error and keep
                    // running to accumulate all such errors.  This function
                    // may return an "okay" for non-error case polymorphics.
                    if (!CanGeneratePropertyIfPolymorphic(pd))
                    {
                        continue;
                    }

                    if (!GenerateNonSerializableProperty(pd))
                    {
                        Type        propType             = CodeGenUtilities.TranslateType(pd.PropertyType);
                        List <Type> typesToCodeGen       = new List <Type>();
                        bool        isTypeSafeToGenerate = true;

                        // Create a list containing the types we will require on the client
                        if (TypeUtility.IsPredefinedDictionaryType(propType))
                        {
                            typesToCodeGen.AddRange(CodeGenUtilities.GetDictionaryGenericArgumentTypes(propType));
                        }
                        else
                        {
                            typesToCodeGen.Add(TypeUtility.GetElementType(propType));
                        }

                        // We consider all predefined types as legal to code-gen *except* those
                        // that would generate a compile error on the client due to missing reference.
                        // We treat "don't know" and "false" as grounds for a warning.
                        // Note that we do this *after* TranslateType so that types like System.Data.Linq.Binary
                        // which cannot exist on the client anyway has been translated
                        foreach (Type type in typesToCodeGen)
                        {
                            // Enum (and nullable<enum>) types may require generation on client
                            Type nonNullableType = TypeUtility.GetNonNullableType(type);


                            if (nonNullableType.IsEnum)
                            {
                                // Register use of this enum type, which could cause deferred generation
                                ClientProxyGenerator.RegisterUseOfEnumType(nonNullableType);
                            }
                            // If this is not an enum or nullable<enum> and we're not generating the complex type, determine whether this
                            // property type is visible to the client.  If it is not, log a warning.
                            else
                            {
                                // "Don't know" counts as "no"
                                CodeMemberShareKind enumShareKind = this.ClientProxyGenerator.GetTypeShareKind(nonNullableType);
                                if ((enumShareKind & CodeMemberShareKind.Shared) == 0)
                                {
                                    this.ClientProxyGenerator.LogWarning(string.Format(CultureInfo.CurrentCulture, Resource.ClientCodeGen_PropertyType_Not_Shared, pd.Name, this.Type.FullName, type.FullName, this.ClientProxyGenerator.ClientProjectName));
                                    isTypeSafeToGenerate = false; // Flag error but continue to allow accumulation of additional errors.
                                }
                            }
                        }

                        if (isTypeSafeToGenerate)
                        {
                            // Generate OnMethodXxxChanging/Changed partial methods.

                            // Note: the parameter type reference needs to handle the possibility the
                            // property type is defined in the project's root namespace and that VB prepends
                            // that namespace.  The utility helper gives us the right type reference.
                            CodeTypeReference parameterTypeRef =
                                CodeGenUtilities.GetTypeReference(propType, ClientProxyGenerator, ProxyClass);

                            NotificationMethodGen.AddMethodFor(pd.Name + "Changing", new CodeParameterDeclarationExpression(parameterTypeRef, "value"), null);
                            NotificationMethodGen.AddMethodFor(pd.Name + "Changed", null);

                            GenerateProperty(pd);
                        }
                    }
                }
                else
                {
                    OnPropertySkipped(pd);
                }
            }
        }
        /// <summary>
        /// Generates a property getter/setter pair into the given proxy class to match the given property info.
        /// </summary>
        /// <param name="propertyDescriptor">PropertyDescriptor for the property to generate for.</param>
        protected virtual void GenerateProperty(PropertyDescriptor propertyDescriptor)
        {
            string propertyName = propertyDescriptor.Name;
            Type   propertyType = CodeGenUtilities.TranslateType(propertyDescriptor.PropertyType);

            // ----------------------------------------------------------------
            // Property type ref
            // ----------------------------------------------------------------
            var propTypeReference = CodeGenUtilities.GetTypeReference(propertyType, ClientProxyGenerator, ProxyClass);

            // ----------------------------------------------------------------
            // Property decl
            // ----------------------------------------------------------------
            var property = new CodeMemberProperty();

            property.Name       = propertyName;
            property.Type       = propTypeReference;
            property.Attributes = MemberAttributes.Public | MemberAttributes.Final; // final needed, else becomes virtual
            List <Attribute> propertyAttributes = propertyDescriptor.ExplicitAttributes().Cast <Attribute>().ToList();

            // Generate <summary> for property
            string comment = string.Format(CultureInfo.CurrentCulture, Resource.CodeGen_Entity_Property_Summary_Comment, propertyName);

            property.Comments.AddRange(CodeGenUtilities.GenerateSummaryCodeComment(comment, ClientProxyGenerator.IsCSharp));

            // ----------------------------------------------------------------
            // [DataMember] -> Add if not already present.
            // ----------------------------------------------------------------
            // Add if not already present.

            if (!propertyAttributes.OfType <DataMemberAttribute>().Any())
            {
                CodeAttributeDeclaration dataMemberAtt = CodeGenUtilities.CreateAttributeDeclaration(typeof(DataMemberAttribute), ClientProxyGenerator, ProxyClass);
                property.CustomAttributes.Add(dataMemberAtt);
            }

            // Here, we check for the existence of [ReadOnly(true)] attributes generated when
            // the property does not not have a setter.  We want to inject an [Editable(false)]
            // attribute into the pipeline.
            ReadOnlyAttribute readOnlyAttr = propertyAttributes.OfType <ReadOnlyAttribute>().SingleOrDefault();

            if (readOnlyAttr != null && !propertyAttributes.OfType <EditableAttribute>().Any())
            {
                propertyAttributes.Add(new EditableAttribute(!readOnlyAttr.IsReadOnly));

                // REVIEW:  should we strip out [ReadOnly] attributes here?
            }

            // Here, we check for the presence of a complex type. If it exists we need to add a DisplayAttribute
            // if not already there. DataSources windows do not handle complex types
            if (TypeUtility.IsSupportedComplexType(propertyType) && !propertyAttributes.OfType <DisplayAttribute>().Any())
            {
                CodeAttributeDeclaration displayAttribute = CodeGenUtilities.CreateDisplayAttributeDeclaration(ClientProxyGenerator, ProxyClass);
                property.CustomAttributes.Add(displayAttribute);
            }

            // ----------------------------------------------------------------
            // Propagate the custom attributes
            // ----------------------------------------------------------------

            CustomAttributeGenerator.GenerateCustomAttributes(
                ClientProxyGenerator,
                ProxyClass,
                ex => string.Format(CultureInfo.CurrentCulture, Resource.ClientCodeGen_Attribute_ThrewException_CodeTypeMember, ex.Message, property.Name, ProxyClass.Name, ex.InnerException.Message),
                propertyAttributes.Cast <Attribute>(),
                property.CustomAttributes,
                property.Comments);

            // ----------------------------------------------------------------
            // backing private field (CodeDom doesn't yet know about auto properties)
            // ----------------------------------------------------------------
            string fieldName = CodeGenUtilities.MakeCompliantFieldName(propertyName);
            var    field     = new CodeMemberField(propTypeReference, fieldName);

            ProxyClass.Members.Add(field);
            var fieldRef = new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), fieldName);
            var valueRef = new CodePropertySetValueReferenceExpression();

            // ----------------------------------------------------------------
            // getter body
            // ----------------------------------------------------------------
            property.GetStatements.Add(new CodeMethodReturnStatement(fieldRef));

            // ----------------------------------------------------------------
            // setter body
            // ----------------------------------------------------------------
            List <CodeStatement> bodyStatements = new List <CodeStatement>();

            // this.OnPropertyXxxChanging(PropType value);
            bodyStatements.Add(NotificationMethodGen.GetMethodInvokeExpressionStatementFor(propertyName + "Changing"));

            bool propertyIsReadOnly = IsPropertyReadOnly(propertyDescriptor);

            if (!propertyIsReadOnly)
            {
                bodyStatements.Add(new CodeExpressionStatement(new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), "RaiseDataMemberChanging", new CodePrimitiveExpression(propertyDescriptor.Name))));
            }

            // Generate the validation tests.
            CodeStatement validationCode = GeneratePropertySetterValidation(propertyDescriptor.Name);

            bodyStatements.Add(validationCode);

            // this._field = value
            bodyStatements.Add(new CodeAssignStatement(fieldRef, valueRef));

            if (!propertyIsReadOnly)
            {
                bodyStatements.Add(new CodeExpressionStatement(new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), "RaiseDataMemberChanged", new CodePrimitiveExpression(propertyDescriptor.Name))));
            }
            else
            {
                // even read-only members need to raise PropertyChanged
                bodyStatements.Add(new CodeExpressionStatement(new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), "RaisePropertyChanged", new CodePrimitiveExpression(propertyDescriptor.Name))));
            }

            // this.OnPropertyXxxChanged();
            bodyStatements.Add(NotificationMethodGen.GetMethodInvokeExpressionStatementFor(propertyName + "Changed"));

            // if (this._field != value)...
            CodeExpression valueTest = CodeGenUtilities.MakeNotEqual(propertyType, fieldRef, valueRef, ClientProxyGenerator.IsCSharp);

            CodeConditionStatement body = new CodeConditionStatement(valueTest, bodyStatements.ToArray <CodeStatement>());

            property.SetStatements.Add(body);

            // add property
            ProxyClass.Members.Add(property);
        }