PropertyEmitter.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / ndp / fx / src / DataEntityDesign / Design / System / Data / EntityModel / Emitters / PropertyEmitter.cs / 1 / PropertyEmitter.cs

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner       [....]
// @backupOwner [....] 
//--------------------------------------------------------------------- 
using System;
using System.CodeDom; 
using System.Data.SqlTypes;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics; 
using System.Data.Metadata.Edm;
using System.Data.EntityModel.SchemaObjectModel; 
using Som = System.Data.EntityModel.SchemaObjectModel; 
using System.Globalization;
using System.Data.Common.Utils; 
using System.Data.Entity.Design;
using System.Data.Entity.Design.Common;
using System.Data.Entity.Design.SsdlGenerator;
using System.Data.Objects.ELinq; 

 
namespace System.Data.EntityModel.Emitters 
{
    ///  
    ///
    /// 
    internal sealed class PropertyEmitter : PropertyEmitterBase
    { 
        private CodeFieldReferenceExpression _fieldRef = null;
        private CodeFieldReferenceExpression _complexPropertyInitializedFieldRef = null; 
 
        // statics
        private const string NestedStoreObjectCollection = "InlineObjectCollection"; 
        private const string DetachFromParentMethodName = "DetachFromParent";

        #region Public Methods
 
        /// 
        /// 
        ///  
        /// 
        ///  
        public PropertyEmitter(ClientApiGenerator generator, EdmProperty property, bool declaringTypeUsesStandardBaseType)
            : base(generator, property, declaringTypeUsesStandardBaseType)
        {
        } 

        ///  
        /// Emit the declaration of the property for the class. 
        /// 
        /// The Property declaration pieces of the CodeDom. 
        public CodeMemberProperty EmitPropertyDeclaration(CodeTypeReference propertyReturnType)
        {
            MemberAttributes scope = AccessibilityFromGettersAndSetters(Item);
            CodeMemberProperty memberProperty = EmitPropertyDeclaration(scope, propertyReturnType, IsVirtualProperty, HidesBaseClassProperty); 

            memberProperty.HasSet = true; 
            memberProperty.HasGet = true; 

            return memberProperty; 
        }

        /// 
        /// Main method for Emitting property code. 
        /// 
        /// The CodeDom representation of the type that the property is being added to. 
        protected override void EmitProperty(CodeTypeDeclaration typeDecl) 
        {
            CodeTypeReference typeRef = PropertyType; 

            // raise the PropertyGenerated event
            //
            PropertyGeneratedEventArgs eventArgs = new PropertyGeneratedEventArgs(Item, FieldName, typeRef); 
            this.Generator.RaisePropertyGeneratedEvent(eventArgs);
 
            // the event subscriber cannot change the return type of the property 
            //
            DisallowReturnTypeChange(typeRef, eventArgs.ReturnType); 

            CodeMemberProperty memberProperty = EmitPropertyDeclaration(eventArgs.ReturnType);
            if (memberProperty == null)
            { 
                return;
            } 
 
            EmitCustomAttributes(memberProperty, eventArgs.AdditionalAttributes);
 
            EmitPropertyGetter(memberProperty, eventArgs.AdditionalGetStatements);
            EmitPropertySetter(memberProperty, eventArgs.AdditionalSetStatements);
            typeDecl.Members.Add(memberProperty);
 
            EmitField(typeDecl, eventArgs.ReturnType);
 
            EmitPropertyOnChangePartialMethods(typeDecl, eventArgs.ReturnType); 
        }
 
        /// 
        /// Emit these methods as "abstract" and fix them up later to be "partial".
        /// CodeDOM does not support partial methods
        ///  
        /// 
        private void EmitPropertyOnChangePartialMethods(CodeTypeDeclaration typeDecl, CodeTypeReference returnType) 
        { 
            CodeMemberMethod onChangingDomMethod = new CodeMemberMethod();
            onChangingDomMethod.Name = OnChangingPartialMethodName(PropertyName); 
            onChangingDomMethod.ReturnType = new CodeTypeReference(typeof(void));
            onChangingDomMethod.Attributes = MemberAttributes.Abstract | MemberAttributes.Public;
            onChangingDomMethod.Parameters.Add(new CodeParameterDeclarationExpression(returnType, "value"));
            typeDecl.Members.Add(onChangingDomMethod); 

            CodeMemberMethod onChangedDomMethod = new CodeMemberMethod(); 
            onChangedDomMethod.Name = OnChangedPartialMethodName(PropertyName); 
            onChangedDomMethod.ReturnType = new CodeTypeReference(typeof(void));
            onChangedDomMethod.Attributes = MemberAttributes.Abstract | MemberAttributes.Public; 
            typeDecl.Members.Add(onChangedDomMethod);

            Generator.FixUps.Add(new FixUp(PropertyClassName + "." + OnChangingPartialMethodName(PropertyName), FixUpType.MarkAbstractMethodAsPartial));
            Generator.FixUps.Add(new FixUp(PropertyClassName + "." + OnChangedPartialMethodName(PropertyName), FixUpType.MarkAbstractMethodAsPartial)); 
        }
 
        private void EmitField(CodeTypeDeclaration typeDecl, CodeTypeReference fieldType) 
        {
            CodeMemberField memberField = new CodeMemberField(fieldType, FieldName); 
            memberField.Attributes = MemberAttributes.Private;
            if (HasDefault(Item))
            {
                memberField.InitExpression = GetDefaultValueExpression(Item); 
            }
 
            typeDecl.Members.Add(memberField); 

            if (Helper.IsComplexType(Item.TypeUsage.EdmType)) 
            {
                CodeMemberField complexInitField = new CodeMemberField(TypeReference.ForType(typeof(bool)), ComplexPropertyInitializedFieldName);
                complexInitField.Attributes = MemberAttributes.Private;
                typeDecl.Members.Add(complexInitField); 
            }
        } 
 
        /// 
        /// Get a reference to the base class DataObject 
        /// 
        public static CodeTypeReferenceExpression CreateEdmStructuralObjectRef(TypeReference typeReference)
        {
            return new CodeTypeReferenceExpression(typeReference.ForType(typeof(System.Data.Objects.DataClasses.StructuralObject))); 
        }
 
        #endregion 
        #region Public Properties
 
        /// 
        ///
        /// 
        public CodeTypeReference PropertyType 
        {
            get 
            { 
                CodeTypeReference typeRef = GetType(Item, false);
                return typeRef; 
            }
        }

        public new EdmProperty Item 
        {
            get 
            { 
                return base.Item as EdmProperty;
            } 
        }

        #endregion
        #region Internal Methods 
        /// 
        /// Name of the associated Entity property for Ref(T) properties 
        ///  
        public string EntityPropertyName
        { 
            get
            {
                return Item.Name;
            } 
        }
 
        #endregion 
        #region Private Methods
        ///  
        ///
        /// 
        /// 
        /// Additional attributes to emit 
        private void EmitCustomAttributes(CodeMemberProperty memberProperty,
                                          List additionalAttributes) 
        { 
            Generator.AttributeEmitter.EmitPropertyAttributes(this, memberProperty, additionalAttributes);
        } 

        private void EmitPropertyGetter(CodeMemberProperty memberProperty, List additionalGetStatements)
        {
            CodeStatementCollection statements = memberProperty.GetStatements; 

            // we need to insert user-specified code before other/existing code, including 
            // the return statement 
            if (additionalGetStatements != null && additionalGetStatements.Count > 0)
            { 
                try
                {
                    CodeStatementCollection getStatements = new CodeStatementCollection();
                    getStatements.AddRange(additionalGetStatements.ToArray()); 
                    if (statements != null && statements.Count > 0)
                    { 
                        getStatements.AddRange(statements); 
                    }
                    statements.Clear(); 
                    statements.AddRange(getStatements);
                }
                catch (ArgumentNullException e)
                { 
                    Generator.AddError(Strings.InvalidGetStatementSuppliedForProperty(Item.Name),
                                       ModelBuilderErrorCode.InvalidGetStatementSuppliedForProperty, 
                                       EdmSchemaErrorSeverity.Error, 
                                       e);
                } 
            }

            MemberAttributes access = memberProperty.Attributes & MemberAttributes.AccessMask;
 
            AddGetterSetterFixUp(Generator.FixUps, PropertyFQName, GetGetterAccessibility(Item), access, true);
 
            EmitPropertyGetterBody(statements); 
        }
 
        /// 
        ///
        /// 
        ///  
        private void EmitPropertyGetterBody(CodeStatementCollection statements)
        { 
            // If the SchemaElement.Type isn't a ComplexType it better be PrimitiveType. 
            if (Helper.IsComplexType(Item.TypeUsage.EdmType))
            { 
                //Since Complex Collections are not supported by
                //the stack, we don't need to do anything special
                //like doing an Attach or Detatch like the way we do for complex types.
                if (GetCollectionKind(Item.TypeUsage) == CollectionKind.None) 
                {
                    // _field = GetValidValue( _field, FieldPropertyInfo, _fieldInitialized); 
                    statements.Add( 
                        new CodeAssignStatement(FieldRef,
                            new CodeMethodInvokeExpression( 
                                    ThisRef,
                                    Utils.GetValidValueMethodName,
                                    new CodeDirectionExpression(FieldDirection.In, FieldRef),
                                    new CodePrimitiveExpression(PropertyName), 
                                    new CodePrimitiveExpression(Item.Nullable),
                                    ComplexPropertyInitializedFieldRef))); 
 
                    // this._complexPropertyInitialized = true;
                    statements.Add( 
                        new CodeAssignStatement(
                            ComplexPropertyInitializedFieldRef,
                            new CodePrimitiveExpression(true)));
                } 
                // return _field;
                statements.Add(new CodeMethodReturnStatement(FieldRef)); 
            } 
            else
            { 
                PrimitiveType primitiveType = Item.TypeUsage.EdmType as PrimitiveType;
                if (primitiveType != null && primitiveType.ClrEquivalentType == typeof(byte[]))
                {
                    // return GetValidValue(_field); 
                    statements.Add(
                        new CodeMethodReturnStatement( 
                            new CodeMethodInvokeExpression( 
                                CreateEdmStructuralObjectRef(TypeReference),
                                Utils.GetValidValueMethodName, 
                                this.FieldRef)));
                }
                else
                { 
                    // for everything else just return the field.
                    statements.Add(new CodeMethodReturnStatement(FieldRef)); 
                } 
            }
        } 


        /// 
        /// 
        /// 
        ///  
        /// Additional statements to emit 
        private void EmitPropertySetter(CodeMemberProperty memberProperty, List additionalSetStatements)
        { 
            CodeStatementCollection statements = memberProperty.SetStatements;

            MemberAttributes access = memberProperty.Attributes & MemberAttributes.AccessMask;
 
            AddGetterSetterFixUp(Generator.FixUps, PropertyFQName, GetSetterAccessibility(Item), access, false);
 
            EmitPropertySetterBody(statements, additionalSetStatements); 
        }
 
        /// 
        /// This is a control function to delegate the creation of the
        /// setter statments to the correct code path
        ///  
        /// The collection that the setter statements should be added to.
        /// Additional statements to emit 
        private void EmitPropertySetterBody(CodeStatementCollection statements, List additionalSetStatements) 
        {
            // Invoke the partial method "On[PropertyName]Changing(); 
            statements.Add(
                new CodeMethodInvokeExpression(
                    ThisRef,
                    OnChangingPartialMethodName(PropertyName), new CodePropertySetValueReferenceExpression())); 

            // ReportPropertyChanging( _piFieldName ); 
            statements.Add( 
                new CodeMethodInvokeExpression(
                    ThisRef, 
                    Utils.ReportPropertyChangingMethodName,
                    new CodePrimitiveExpression(PropertyName)));

            // insert additional statements following the PropertyChanging event 
            if (additionalSetStatements != null && additionalSetStatements.Count > 0)
            { 
                try 
                {
                    statements.AddRange(additionalSetStatements.ToArray()); 
                }
                catch (ArgumentNullException e)
                {
                    Generator.AddError(Strings.InvalidSetStatementSuppliedForProperty(Item.Name), 
                                       ModelBuilderErrorCode.InvalidSetStatementSuppliedForProperty,
                                       EdmSchemaErrorSeverity.Error, 
                                       e); 
                }
            } 

            if (TypeSemantics.IsPrimitiveType(Item.TypeUsage))
            {
                EmitScalarTypePropertySetStatements(statements, CollectionKind.None); 
            }
            else if (TypeSemantics.IsComplexType(Item.TypeUsage)) 
            { 
                // ComplexTypes have a completely different set pattern:
                EmitComplexTypePropertySetStatements(statements, CollectionKind.None); 
            }
            else if (TypeSemantics.IsCollectionType(Item.TypeUsage))
            {
                if (TypeSemantics.IsComplexType(((CollectionType)Item.TypeUsage.EdmType).TypeUsage)) 
                {
                    EmitComplexTypePropertySetStatements(statements, GetCollectionKind(Item.TypeUsage)); 
                } 
                else
                { 
                    Debug.Assert(TypeSemantics.IsPrimitiveType(((CollectionType)Item.TypeUsage.EdmType).TypeUsage),
                        "Collections should be of primitive types or complex types");
                    EmitScalarTypePropertySetStatements(statements, GetCollectionKind(Item.TypeUsage));
                } 

            } 
            else if (TypeSemantics.IsEnumerationType(Item.TypeUsage)) 
            {
                // this.fieldName = value; 
                statements.Add(
                    new CodeAssignStatement(
                            FieldRef,
                            new CodePropertySetValueReferenceExpression())); 

            } 
 
            // ReportPropertyChanged( _piFieldName );
            statements.Add( 
                new CodeMethodInvokeExpression(
                    ThisRef,
                    Utils.ReportPropertyChangedMethodName,
                    new CodePrimitiveExpression(PropertyName))); 

            // Invoke the partial method "On[PropertyName]Changed(); 
            statements.Add( 
                new CodeMethodInvokeExpression(
                    ThisRef, 
                    OnChangedPartialMethodName(PropertyName)));
        }

        ///  
        /// Do the fixups to allow get and set statements in properties
        /// to have different accessibility than the property itself. 
        ///  
        /// The accessibility for the getter or setter
        /// The property's accessibility 
        /// True if this is a getter, false if a setter
        internal static void AddGetterSetterFixUp(FixUpCollection fixups, string propertyFqName, MemberAttributes accessibility, MemberAttributes propertyAccessibility, bool isGetter)
        {
            Debug.Assert(GetAccessibilityRank(accessibility) >= 0, "bad accessibility"); 

            // Private 
            if (accessibility == MemberAttributes.Private && propertyAccessibility != MemberAttributes.Private) 
            {
                if (isGetter) 
                {
                    fixups.Add(new FixUp(propertyFqName, FixUpType.MarkPropertyGetAsPrivate));
                }
                else 
                {
                    fixups.Add(new FixUp(propertyFqName, FixUpType.MarkPropertySetAsPrivate)); 
                } 
            }
 
            // Internal
            if (accessibility == MemberAttributes.Assembly && propertyAccessibility != MemberAttributes.Assembly)
            {
                if (isGetter) 
                {
                    fixups.Add(new FixUp(propertyFqName, FixUpType.MarkPropertyGetAsInternal)); 
                } 
                else
                { 
                    fixups.Add(new FixUp(propertyFqName, FixUpType.MarkPropertySetAsInternal));
                }
            }
 
            // Public
            if (accessibility == MemberAttributes.Public && propertyAccessibility != MemberAttributes.Public) 
            { 
                if (isGetter)
                { 
                    fixups.Add(new FixUp(propertyFqName, FixUpType.MarkPropertyGetAsPublic));
                }
                else
                { 
                    fixups.Add(new FixUp(propertyFqName, FixUpType.MarkPropertySetAsPublic));
                } 
            } 

            // Protected 
            if (accessibility == MemberAttributes.Family && propertyAccessibility != MemberAttributes.Family)
            {
                if (isGetter)
                { 
                    fixups.Add(new FixUp(propertyFqName, FixUpType.MarkPropertyGetAsProtected));
                } 
                else 
                {
                    fixups.Add(new FixUp(propertyFqName, FixUpType.MarkPropertySetAsProtected)); 
                }
            }

        } 

        ///  
        /// Emit the set statements for a property that is a scalar type 
        /// 
        /// The statement collection to add the set statements to. 
        private void EmitScalarTypePropertySetStatements(CodeStatementCollection statements,
            CollectionKind collectionKind)
        {
            Debug.Assert(statements != null, "statments can't be null"); 
            Debug.Assert(((TypeSemantics.IsPrimitiveType(Item.TypeUsage)) || (TypeSemantics.IsCollectionType(Item.TypeUsage)))
                , "Must be a primitive type or collection type property"); 
 
            CodePropertySetValueReferenceExpression valueRef = new CodePropertySetValueReferenceExpression();
            //Since collections are not supported by 
            //the stack, we don't need to do anything special
            //like doing an Attach or Detatch like the way we do for complex types.
            if (collectionKind == CollectionKind.None)
            { 

                PrimitiveType primitiveType = (PrimitiveType)Item.TypeUsage.EdmType; 
 
                // basic pattern
                // this.fieldName = SetValidValue( value ); 
                //
                List parameters = new List();
                parameters.Add(valueRef);
 

                // pattern for non Nullable types (string, byte[]) 
                // 
                // this.fieldName = SetValidVaue( value, nullability );
 
                if (primitiveType.ClrEquivalentType.IsClass)
                {
                    // ref types have an extra boolean parameter to tell if the property is allowed to
                    // be null or not 
                    parameters.Add(new CodePrimitiveExpression(Item.Nullable));
                } 
 
                // now create and add the built statement
                statements.Add( 
                    new CodeAssignStatement(
                            FieldRef,
                            new CodeMethodInvokeExpression(
                                CreateEdmStructuralObjectRef(TypeReference), 
                                Utils.SetValidValueMethodName,
                                parameters.ToArray()))); 
            } 
            else
            { 
                // this.fieldName = value;
                statements.Add(
                    new CodeAssignStatement(
                        FieldRef, valueRef)); 

            } 
        } 

        private CodeExpression GetEnumValue(T value) 
        {
            Type type = typeof(T);
            return new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(TypeReference.ForType(type)), Enum.GetName(type, value));
        } 

 
        ///  
        /// Emit the property set statments to properly set a ComplexType.
        ///  
        /// The collection of statements that the set statements should be added to.
        private void EmitComplexTypePropertySetStatements(CodeStatementCollection statements, CollectionKind collectionKind)
        {
            CodePropertySetValueReferenceExpression valueRef = new CodePropertySetValueReferenceExpression(); 
            //Since collections are not supported by
            //the stack, we don't need to do anything special 
            //like doing an Attach or Detatch like the way we do for complex types. 
            if (collectionKind == CollectionKind.None)
            { 

                // this.fieldName = SetValidValue( this.fieldName, value, _pifieldName);
                statements.Add(
                    new CodeAssignStatement( 
                        FieldRef,
                        new CodeMethodInvokeExpression( 
                                ThisRef, 
                                Utils.SetValidValueMethodName,
                                FieldRef, 
                                valueRef,
                                new CodePrimitiveExpression(PropertyName))));

                // this._complexPropertyInitialized = true; 
                statements.Add(
                    new CodeAssignStatement( 
                        ComplexPropertyInitializedFieldRef, 
                        new CodePrimitiveExpression(true)));
            } 
            else
            {
                // this.fieldName = value;
                statements.Add( 
                    new CodeAssignStatement(
                        FieldRef, valueRef)); 
 
            }
 
        }

        /// 
        /// See if a property names will hide a base class member name 
        /// 
        private bool HidesBaseClassProperty 
        { 
            get
            { 
                StructuralType parentBaseClass = Item.DeclaringType.BaseType as StructuralType;
                if (parentBaseClass != null && parentBaseClass.Members.Contains(PropertyName))
                    return true;
 
                return false;
            } 
        } 

        ///  
        ///
        /// 
        /// 
        ///  
        /// 
        private CodeTypeReference GetType(EdmProperty property, bool getElementType) 
        { 
            PropertyTypeReferences types = default(PropertyTypeReferences);
            EdmType propertyType = property.TypeUsage.EdmType; 

            // Initialize types
            if (Helper.IsPrimitiveType(propertyType))
            { 
                types = new PropertyTypeReferences(TypeReference, (PrimitiveType)propertyType);
            } 
            else if (Helper.IsComplexType(propertyType)) 
            {
                types = new PropertyTypeReferences(TypeReference, (ComplexType)propertyType, Generator); 
            }
            else if (Helper.IsCollectionType(propertyType))
            {
                TypeUsage typeUsage = ((CollectionType)propertyType).TypeUsage; 
                if (Helper.IsPrimitiveType(typeUsage.EdmType))
                { 
                    types = new PropertyTypeReferences(TypeReference, (PrimitiveType)typeUsage.EdmType, GetCollectionKind(property.TypeUsage)); 
                }
                else 
                {
                    Debug.Assert(Helper.IsComplexType(typeUsage.EdmType));
                    types = new PropertyTypeReferences(TypeReference, (ComplexType)typeUsage.EdmType, GetCollectionKind(property.TypeUsage), Generator);
                } 
            }
            else 
            { 
                // shouldn't be able to get here....
                Debug.Fail("Unexpected Property.Type type: " + propertyType.GetType()); 
            }

            // Set types, or retrieve existing types if they have been set in the interim
            // Don't cache Collection types since CollectionKind is really a facet and 
            //it is not part of the key we are using for the dictionary used to cache.
            if (!Helper.IsCollectionType(propertyType)) 
            { 
                Debug.Assert(types.NonNullable != null && types.Nullable != null, "did you forget to set the types variable?");
            } 

            if (property.Nullable)
            {
                return types.Nullable; 
            }
            else 
            { 
                return types.NonNullable;
            } 
        }


        private static CollectionKind GetCollectionKind(TypeUsage usage) 
        {
            Facet collectionFacet; 
            if (usage.Facets.TryGetValue(EdmConstants.CollectionKind, false, out collectionFacet)) 
            {
                return (CollectionKind)collectionFacet.Value; 
            }

            return CollectionKind.None;
        } 

        private string OnChangingPartialMethodName(string propertyName) { return "On" + propertyName + "Changing"; } 
        private string OnChangedPartialMethodName(string propertyName) { return "On" + propertyName + "Changed"; } 

        #endregion 

        #region Private Properties
        /// 
        /// 
        /// 
        private CodeFieldReferenceExpression FieldRef 
        { 
            get
            { 
                if (_fieldRef == null)
                    _fieldRef = new CodeFieldReferenceExpression(ThisRef, FieldName);

                return _fieldRef; 
            }
        } 
        ///  
        ///
        ///  
        private CodeFieldReferenceExpression ComplexPropertyInitializedFieldRef
        {
            get
            { 
                if (_complexPropertyInitializedFieldRef == null)
                    _complexPropertyInitializedFieldRef = new CodeFieldReferenceExpression(ThisRef, ComplexPropertyInitializedFieldName); 
 
                return _complexPropertyInitializedFieldRef;
            } 
        }
        /// 
        ///
        ///  
        private string FieldName
        { 
            get 
            {
                return Utils.FieldNameFromPropName(PropertyName); 
            }
        }
        /// 
        /// 
        /// 
        private string ComplexPropertyInitializedFieldName 
        { 
            get
            { 
                return Utils.ComplexPropertyInitializedNameFromPropName(PropertyName);
            }
        }
 
        internal bool IsKeyProperty
        { 
            get 
            {
                EntityType entity = Item.DeclaringType as EntityType; 
                if (entity != null)
                {
                    return entity.KeyMembers.Contains(Item.Name);
                } 
                return false;
            } 
        } 

        ///  
        ///
        /// 
        internal static bool HasDefault(EdmProperty property)
        { 
            return property.DefaultValue != null;
        } 
 
        /// 
        /// 
        /// 
        private CodeExpression GetDefaultValueExpression(EdmProperty property)
        {
            PrimitiveTypeKind type; 
            object value = property.DefaultValue;
            if (value != null 
                 && Utils.TryGetPrimitiveTypeKind(property.TypeUsage.EdmType, out type)) 
            {
                switch (type) 
                {
                    case PrimitiveTypeKind.Boolean:
                    case PrimitiveTypeKind.Byte:
                    case PrimitiveTypeKind.Int16: 
                    case PrimitiveTypeKind.Int32:
                    case PrimitiveTypeKind.Int64: 
                    case PrimitiveTypeKind.Decimal: 
                    case PrimitiveTypeKind.Single:
                    case PrimitiveTypeKind.Double: 
                    case PrimitiveTypeKind.String:
                        {
                            if (!property.Nullable && value.Equals(TypeSystem.GetDefaultValue(value.GetType())))
                            { 
                                break;
                            } 
                            return new CodePrimitiveExpression(value); 
                        }
                    case PrimitiveTypeKind.Guid: 
                        {
                            if (!property.Nullable && value.Equals(TypeSystem.GetDefaultValue(value.GetType())))
                            {
                                break; 
                            }
                            return GetCodeExpressionFromGuid(value); 
                        } 
                    case PrimitiveTypeKind.DateTime:
                        { 
                            if (!property.Nullable && value.Equals(TypeSystem.GetDefaultValue(value.GetType())))
                            {
                                break;
                            } 
                            return GetCodeExpressionFromDateTimeDefaultValue(value, property);
                        } 
                    case PrimitiveTypeKind.Binary: 
                        {
                            return GetCodeExpressionFromBinary(value); 
                        }
                }
                return null;
            } 

            return null; 
        } 

        ///  
        ///
        /// 
        private CodeExpression GetCodeExpressionFromBinary(object value)
        { 
            byte[] data = (byte[])value;
            CodeExpression[] bytes = new CodeExpression[data.Length]; 
 
            for (int iByte = 0; iByte < data.Length; ++iByte)
            { 
                bytes[iByte] = new CodePrimitiveExpression(data[iByte]);
            }

            return new CodeArrayCreateExpression(TypeReference.ByteArray, bytes); 
        }
 
        ///  
        ///
        ///  
        /// 
        private CodeExpression GetCodeExpressionFromGuid(object value)
        {
            Guid guid = (Guid)value; 
            return new CodeObjectCreateExpression(TypeReference.Guid,
                new CodePrimitiveExpression(guid.ToString("D", CultureInfo.InvariantCulture))); 
        } 

        ///  
        ///
        /// 
        private CodeExpression GetCodeExpressionFromDateTimeDefaultValue(object value, EdmProperty property)
        { 
            DateTime utc = (DateTime)value;
            DateTime dateTime = DateTime.SpecifyKind(utc, DateTimeKind.Unspecified); 
 

            return new CodeObjectCreateExpression(TypeReference.DateTime, new CodePrimitiveExpression(dateTime.Ticks), GetEnumValue(DateTimeKind.Unspecified)); 
        }

        /// 
        /// 
        /// 
        public bool IsVirtualProperty 
        { 
            get
            { 
                return false;
            }
        }
 
        private struct PropertyTypeReferences
        { 
            CodeTypeReference _nonNullable; 
            CodeTypeReference _nullable;
            public PropertyTypeReferences(TypeReference typeReference, PrimitiveType primitiveType) 
                : this(typeReference, primitiveType, CollectionKind.None)
            {
            }
 
            public PropertyTypeReferences(TypeReference typeReference, PrimitiveType primitiveType, CollectionKind collectionKind)
            { 
                Type type = primitiveType.ClrEquivalentType; 
                if (collectionKind == CollectionKind.None)
                { 
                    _nonNullable = typeReference.ForType(type);
                    if (type.IsValueType)
                    {
                        _nullable = typeReference.NullableForType(type); 
                    }
                    else 
                    { 
                        _nullable = typeReference.ForType(type);
                    } 
                }
                else
                {
                    CodeTypeReference primitiveTypeRef = typeReference.ForType(type); 
                    CodeTypeReference collectionType = GetCollectionTypeReference(typeReference, primitiveTypeRef, collectionKind);
                    _nonNullable = collectionType; 
                    _nullable = collectionType; 
                }
            } 

            public PropertyTypeReferences(TypeReference typeReference, ComplexType complexType, CollectionKind collectionKind, ClientApiGenerator generator)
            {
                CodeTypeReference baseType = generator.GetLeastPossibleQualifiedTypeReference(complexType); 
                baseType = GetCollectionTypeReference(typeReference, baseType, collectionKind);
                _nonNullable = baseType; 
                _nullable = baseType; 
            }
 
            private static CodeTypeReference GetCollectionTypeReference(TypeReference typeReference, CodeTypeReference baseType, CollectionKind collectionKind)
            {
                if (collectionKind == CollectionKind.Bag)
                { 
                    baseType = GetCollectionTypeReferenceForBagSemantics(typeReference, baseType);
                } 
                else if (collectionKind == CollectionKind.List) 
                {
                    baseType = GetCollectionTypeReferenceForListSemantics(typeReference, baseType); 
                }
                else
                {
                    Debug.Assert(collectionKind == CollectionKind.None, "Was another CollectionKind value added"); 
                    // nothing more to do for .None
                } 
                return baseType; 
            }
 
            public PropertyTypeReferences(TypeReference typeReference, ComplexType complexType, ClientApiGenerator generator)
                : this(typeReference, complexType, CollectionKind.None, generator)
            {
            } 

            private static CodeTypeReference GetCollectionTypeReferenceForBagSemantics(TypeReference typeReference, CodeTypeReference baseType) 
            { 
                CodeTypeReference typeRef = typeReference.ForType(typeof(System.Collections.Generic.ICollection<>), baseType);
                return typeRef; 
            }

            private static CodeTypeReference GetCollectionTypeReferenceForListSemantics(TypeReference typeReference, CodeTypeReference baseType)
            { 
                CodeTypeReference typeRef = typeReference.ForType(typeof(System.Collections.Generic.IList<>), baseType);
                return typeRef; 
            } 

            public CodeTypeReference NonNullable 
            {
                get { return _nonNullable; }
            }
            public CodeTypeReference Nullable 
            {
                get { return _nullable; } 
            } 
        }
        #endregion 



        // properties from ClassPropertyEmitter 

        public string PropertyFQName 
        { 
            get
            { 
                return Item.DeclaringType.FullName + "." + Item.Name;
            }
        }
 
        public string PropertyName
        { 
            get 
            {
                return EntityPropertyName; 
            }
        }

        private string PropertyClassName 
        {
            get 
            { 
                return Item.DeclaringType.Name;
            } 
        }

        private CodeMemberProperty EmitPropertyDeclaration(MemberAttributes scope, CodeTypeReference propertyType, bool isVirtual,
            bool hidesBaseProperty) 
        {
            Debug.Assert(GetAccessibilityRank(scope) >= 0, "scope should only be an accessibility attribute"); 
 
            CodeMemberProperty memberProperty = new CodeMemberProperty();
            memberProperty.Name = PropertyName; 
            CommentEmitter.EmitSummaryComments(Item, memberProperty.Comments);

            memberProperty.Attributes = scope;
 
            if (!isVirtual)
            { 
                memberProperty.Attributes |= MemberAttributes.Final; 
            }
 
            if (hidesBaseProperty || AncestorClassDefinesName(memberProperty.Name))
            {
                memberProperty.Attributes |= MemberAttributes.New;
            } 

            memberProperty.Type = propertyType; 
 
            return memberProperty;
        } 


        private void DisallowReturnTypeChange(CodeTypeReference baseType, CodeTypeReference newType)
        { 
            if (Helper.IsCollectionType(Item.TypeUsage.EdmType) && GetCollectionKind(Item.TypeUsage) != CollectionKind.None)
            { 
                if (newType == null) 
                {
                    throw EDesignUtil.InvalidOperation(Strings.CannotChangePropertyReturnTypeToNull(Item.Name, Item.DeclaringType.Name)); 
                }

                // you can change the return type of collection properties
                // we don't even need to check 
                return;
            } 
 

            if (!(baseType == null && newType == null) && 
                (
                    (baseType != null && !baseType.Equals(newType)) ||
                    (newType != null && !newType.Equals(baseType))
                ) 
               )
            { 
                throw EDesignUtil.InvalidOperation(Strings.CannotChangePropertyReturnType(Item.Name, Item.DeclaringType.Name)); 
            }
        } 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner       [....]
// @backupOwner [....] 
//--------------------------------------------------------------------- 
using System;
using System.CodeDom; 
using System.Data.SqlTypes;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics; 
using System.Data.Metadata.Edm;
using System.Data.EntityModel.SchemaObjectModel; 
using Som = System.Data.EntityModel.SchemaObjectModel; 
using System.Globalization;
using System.Data.Common.Utils; 
using System.Data.Entity.Design;
using System.Data.Entity.Design.Common;
using System.Data.Entity.Design.SsdlGenerator;
using System.Data.Objects.ELinq; 

 
namespace System.Data.EntityModel.Emitters 
{
    ///  
    ///
    /// 
    internal sealed class PropertyEmitter : PropertyEmitterBase
    { 
        private CodeFieldReferenceExpression _fieldRef = null;
        private CodeFieldReferenceExpression _complexPropertyInitializedFieldRef = null; 
 
        // statics
        private const string NestedStoreObjectCollection = "InlineObjectCollection"; 
        private const string DetachFromParentMethodName = "DetachFromParent";

        #region Public Methods
 
        /// 
        /// 
        ///  
        /// 
        ///  
        public PropertyEmitter(ClientApiGenerator generator, EdmProperty property, bool declaringTypeUsesStandardBaseType)
            : base(generator, property, declaringTypeUsesStandardBaseType)
        {
        } 

        ///  
        /// Emit the declaration of the property for the class. 
        /// 
        /// The Property declaration pieces of the CodeDom. 
        public CodeMemberProperty EmitPropertyDeclaration(CodeTypeReference propertyReturnType)
        {
            MemberAttributes scope = AccessibilityFromGettersAndSetters(Item);
            CodeMemberProperty memberProperty = EmitPropertyDeclaration(scope, propertyReturnType, IsVirtualProperty, HidesBaseClassProperty); 

            memberProperty.HasSet = true; 
            memberProperty.HasGet = true; 

            return memberProperty; 
        }

        /// 
        /// Main method for Emitting property code. 
        /// 
        /// The CodeDom representation of the type that the property is being added to. 
        protected override void EmitProperty(CodeTypeDeclaration typeDecl) 
        {
            CodeTypeReference typeRef = PropertyType; 

            // raise the PropertyGenerated event
            //
            PropertyGeneratedEventArgs eventArgs = new PropertyGeneratedEventArgs(Item, FieldName, typeRef); 
            this.Generator.RaisePropertyGeneratedEvent(eventArgs);
 
            // the event subscriber cannot change the return type of the property 
            //
            DisallowReturnTypeChange(typeRef, eventArgs.ReturnType); 

            CodeMemberProperty memberProperty = EmitPropertyDeclaration(eventArgs.ReturnType);
            if (memberProperty == null)
            { 
                return;
            } 
 
            EmitCustomAttributes(memberProperty, eventArgs.AdditionalAttributes);
 
            EmitPropertyGetter(memberProperty, eventArgs.AdditionalGetStatements);
            EmitPropertySetter(memberProperty, eventArgs.AdditionalSetStatements);
            typeDecl.Members.Add(memberProperty);
 
            EmitField(typeDecl, eventArgs.ReturnType);
 
            EmitPropertyOnChangePartialMethods(typeDecl, eventArgs.ReturnType); 
        }
 
        /// 
        /// Emit these methods as "abstract" and fix them up later to be "partial".
        /// CodeDOM does not support partial methods
        ///  
        /// 
        private void EmitPropertyOnChangePartialMethods(CodeTypeDeclaration typeDecl, CodeTypeReference returnType) 
        { 
            CodeMemberMethod onChangingDomMethod = new CodeMemberMethod();
            onChangingDomMethod.Name = OnChangingPartialMethodName(PropertyName); 
            onChangingDomMethod.ReturnType = new CodeTypeReference(typeof(void));
            onChangingDomMethod.Attributes = MemberAttributes.Abstract | MemberAttributes.Public;
            onChangingDomMethod.Parameters.Add(new CodeParameterDeclarationExpression(returnType, "value"));
            typeDecl.Members.Add(onChangingDomMethod); 

            CodeMemberMethod onChangedDomMethod = new CodeMemberMethod(); 
            onChangedDomMethod.Name = OnChangedPartialMethodName(PropertyName); 
            onChangedDomMethod.ReturnType = new CodeTypeReference(typeof(void));
            onChangedDomMethod.Attributes = MemberAttributes.Abstract | MemberAttributes.Public; 
            typeDecl.Members.Add(onChangedDomMethod);

            Generator.FixUps.Add(new FixUp(PropertyClassName + "." + OnChangingPartialMethodName(PropertyName), FixUpType.MarkAbstractMethodAsPartial));
            Generator.FixUps.Add(new FixUp(PropertyClassName + "." + OnChangedPartialMethodName(PropertyName), FixUpType.MarkAbstractMethodAsPartial)); 
        }
 
        private void EmitField(CodeTypeDeclaration typeDecl, CodeTypeReference fieldType) 
        {
            CodeMemberField memberField = new CodeMemberField(fieldType, FieldName); 
            memberField.Attributes = MemberAttributes.Private;
            if (HasDefault(Item))
            {
                memberField.InitExpression = GetDefaultValueExpression(Item); 
            }
 
            typeDecl.Members.Add(memberField); 

            if (Helper.IsComplexType(Item.TypeUsage.EdmType)) 
            {
                CodeMemberField complexInitField = new CodeMemberField(TypeReference.ForType(typeof(bool)), ComplexPropertyInitializedFieldName);
                complexInitField.Attributes = MemberAttributes.Private;
                typeDecl.Members.Add(complexInitField); 
            }
        } 
 
        /// 
        /// Get a reference to the base class DataObject 
        /// 
        public static CodeTypeReferenceExpression CreateEdmStructuralObjectRef(TypeReference typeReference)
        {
            return new CodeTypeReferenceExpression(typeReference.ForType(typeof(System.Data.Objects.DataClasses.StructuralObject))); 
        }
 
        #endregion 
        #region Public Properties
 
        /// 
        ///
        /// 
        public CodeTypeReference PropertyType 
        {
            get 
            { 
                CodeTypeReference typeRef = GetType(Item, false);
                return typeRef; 
            }
        }

        public new EdmProperty Item 
        {
            get 
            { 
                return base.Item as EdmProperty;
            } 
        }

        #endregion
        #region Internal Methods 
        /// 
        /// Name of the associated Entity property for Ref(T) properties 
        ///  
        public string EntityPropertyName
        { 
            get
            {
                return Item.Name;
            } 
        }
 
        #endregion 
        #region Private Methods
        ///  
        ///
        /// 
        /// 
        /// Additional attributes to emit 
        private void EmitCustomAttributes(CodeMemberProperty memberProperty,
                                          List additionalAttributes) 
        { 
            Generator.AttributeEmitter.EmitPropertyAttributes(this, memberProperty, additionalAttributes);
        } 

        private void EmitPropertyGetter(CodeMemberProperty memberProperty, List additionalGetStatements)
        {
            CodeStatementCollection statements = memberProperty.GetStatements; 

            // we need to insert user-specified code before other/existing code, including 
            // the return statement 
            if (additionalGetStatements != null && additionalGetStatements.Count > 0)
            { 
                try
                {
                    CodeStatementCollection getStatements = new CodeStatementCollection();
                    getStatements.AddRange(additionalGetStatements.ToArray()); 
                    if (statements != null && statements.Count > 0)
                    { 
                        getStatements.AddRange(statements); 
                    }
                    statements.Clear(); 
                    statements.AddRange(getStatements);
                }
                catch (ArgumentNullException e)
                { 
                    Generator.AddError(Strings.InvalidGetStatementSuppliedForProperty(Item.Name),
                                       ModelBuilderErrorCode.InvalidGetStatementSuppliedForProperty, 
                                       EdmSchemaErrorSeverity.Error, 
                                       e);
                } 
            }

            MemberAttributes access = memberProperty.Attributes & MemberAttributes.AccessMask;
 
            AddGetterSetterFixUp(Generator.FixUps, PropertyFQName, GetGetterAccessibility(Item), access, true);
 
            EmitPropertyGetterBody(statements); 
        }
 
        /// 
        ///
        /// 
        ///  
        private void EmitPropertyGetterBody(CodeStatementCollection statements)
        { 
            // If the SchemaElement.Type isn't a ComplexType it better be PrimitiveType. 
            if (Helper.IsComplexType(Item.TypeUsage.EdmType))
            { 
                //Since Complex Collections are not supported by
                //the stack, we don't need to do anything special
                //like doing an Attach or Detatch like the way we do for complex types.
                if (GetCollectionKind(Item.TypeUsage) == CollectionKind.None) 
                {
                    // _field = GetValidValue( _field, FieldPropertyInfo, _fieldInitialized); 
                    statements.Add( 
                        new CodeAssignStatement(FieldRef,
                            new CodeMethodInvokeExpression( 
                                    ThisRef,
                                    Utils.GetValidValueMethodName,
                                    new CodeDirectionExpression(FieldDirection.In, FieldRef),
                                    new CodePrimitiveExpression(PropertyName), 
                                    new CodePrimitiveExpression(Item.Nullable),
                                    ComplexPropertyInitializedFieldRef))); 
 
                    // this._complexPropertyInitialized = true;
                    statements.Add( 
                        new CodeAssignStatement(
                            ComplexPropertyInitializedFieldRef,
                            new CodePrimitiveExpression(true)));
                } 
                // return _field;
                statements.Add(new CodeMethodReturnStatement(FieldRef)); 
            } 
            else
            { 
                PrimitiveType primitiveType = Item.TypeUsage.EdmType as PrimitiveType;
                if (primitiveType != null && primitiveType.ClrEquivalentType == typeof(byte[]))
                {
                    // return GetValidValue(_field); 
                    statements.Add(
                        new CodeMethodReturnStatement( 
                            new CodeMethodInvokeExpression( 
                                CreateEdmStructuralObjectRef(TypeReference),
                                Utils.GetValidValueMethodName, 
                                this.FieldRef)));
                }
                else
                { 
                    // for everything else just return the field.
                    statements.Add(new CodeMethodReturnStatement(FieldRef)); 
                } 
            }
        } 


        /// 
        /// 
        /// 
        ///  
        /// Additional statements to emit 
        private void EmitPropertySetter(CodeMemberProperty memberProperty, List additionalSetStatements)
        { 
            CodeStatementCollection statements = memberProperty.SetStatements;

            MemberAttributes access = memberProperty.Attributes & MemberAttributes.AccessMask;
 
            AddGetterSetterFixUp(Generator.FixUps, PropertyFQName, GetSetterAccessibility(Item), access, false);
 
            EmitPropertySetterBody(statements, additionalSetStatements); 
        }
 
        /// 
        /// This is a control function to delegate the creation of the
        /// setter statments to the correct code path
        ///  
        /// The collection that the setter statements should be added to.
        /// Additional statements to emit 
        private void EmitPropertySetterBody(CodeStatementCollection statements, List additionalSetStatements) 
        {
            // Invoke the partial method "On[PropertyName]Changing(); 
            statements.Add(
                new CodeMethodInvokeExpression(
                    ThisRef,
                    OnChangingPartialMethodName(PropertyName), new CodePropertySetValueReferenceExpression())); 

            // ReportPropertyChanging( _piFieldName ); 
            statements.Add( 
                new CodeMethodInvokeExpression(
                    ThisRef, 
                    Utils.ReportPropertyChangingMethodName,
                    new CodePrimitiveExpression(PropertyName)));

            // insert additional statements following the PropertyChanging event 
            if (additionalSetStatements != null && additionalSetStatements.Count > 0)
            { 
                try 
                {
                    statements.AddRange(additionalSetStatements.ToArray()); 
                }
                catch (ArgumentNullException e)
                {
                    Generator.AddError(Strings.InvalidSetStatementSuppliedForProperty(Item.Name), 
                                       ModelBuilderErrorCode.InvalidSetStatementSuppliedForProperty,
                                       EdmSchemaErrorSeverity.Error, 
                                       e); 
                }
            } 

            if (TypeSemantics.IsPrimitiveType(Item.TypeUsage))
            {
                EmitScalarTypePropertySetStatements(statements, CollectionKind.None); 
            }
            else if (TypeSemantics.IsComplexType(Item.TypeUsage)) 
            { 
                // ComplexTypes have a completely different set pattern:
                EmitComplexTypePropertySetStatements(statements, CollectionKind.None); 
            }
            else if (TypeSemantics.IsCollectionType(Item.TypeUsage))
            {
                if (TypeSemantics.IsComplexType(((CollectionType)Item.TypeUsage.EdmType).TypeUsage)) 
                {
                    EmitComplexTypePropertySetStatements(statements, GetCollectionKind(Item.TypeUsage)); 
                } 
                else
                { 
                    Debug.Assert(TypeSemantics.IsPrimitiveType(((CollectionType)Item.TypeUsage.EdmType).TypeUsage),
                        "Collections should be of primitive types or complex types");
                    EmitScalarTypePropertySetStatements(statements, GetCollectionKind(Item.TypeUsage));
                } 

            } 
            else if (TypeSemantics.IsEnumerationType(Item.TypeUsage)) 
            {
                // this.fieldName = value; 
                statements.Add(
                    new CodeAssignStatement(
                            FieldRef,
                            new CodePropertySetValueReferenceExpression())); 

            } 
 
            // ReportPropertyChanged( _piFieldName );
            statements.Add( 
                new CodeMethodInvokeExpression(
                    ThisRef,
                    Utils.ReportPropertyChangedMethodName,
                    new CodePrimitiveExpression(PropertyName))); 

            // Invoke the partial method "On[PropertyName]Changed(); 
            statements.Add( 
                new CodeMethodInvokeExpression(
                    ThisRef, 
                    OnChangedPartialMethodName(PropertyName)));
        }

        ///  
        /// Do the fixups to allow get and set statements in properties
        /// to have different accessibility than the property itself. 
        ///  
        /// The accessibility for the getter or setter
        /// The property's accessibility 
        /// True if this is a getter, false if a setter
        internal static void AddGetterSetterFixUp(FixUpCollection fixups, string propertyFqName, MemberAttributes accessibility, MemberAttributes propertyAccessibility, bool isGetter)
        {
            Debug.Assert(GetAccessibilityRank(accessibility) >= 0, "bad accessibility"); 

            // Private 
            if (accessibility == MemberAttributes.Private && propertyAccessibility != MemberAttributes.Private) 
            {
                if (isGetter) 
                {
                    fixups.Add(new FixUp(propertyFqName, FixUpType.MarkPropertyGetAsPrivate));
                }
                else 
                {
                    fixups.Add(new FixUp(propertyFqName, FixUpType.MarkPropertySetAsPrivate)); 
                } 
            }
 
            // Internal
            if (accessibility == MemberAttributes.Assembly && propertyAccessibility != MemberAttributes.Assembly)
            {
                if (isGetter) 
                {
                    fixups.Add(new FixUp(propertyFqName, FixUpType.MarkPropertyGetAsInternal)); 
                } 
                else
                { 
                    fixups.Add(new FixUp(propertyFqName, FixUpType.MarkPropertySetAsInternal));
                }
            }
 
            // Public
            if (accessibility == MemberAttributes.Public && propertyAccessibility != MemberAttributes.Public) 
            { 
                if (isGetter)
                { 
                    fixups.Add(new FixUp(propertyFqName, FixUpType.MarkPropertyGetAsPublic));
                }
                else
                { 
                    fixups.Add(new FixUp(propertyFqName, FixUpType.MarkPropertySetAsPublic));
                } 
            } 

            // Protected 
            if (accessibility == MemberAttributes.Family && propertyAccessibility != MemberAttributes.Family)
            {
                if (isGetter)
                { 
                    fixups.Add(new FixUp(propertyFqName, FixUpType.MarkPropertyGetAsProtected));
                } 
                else 
                {
                    fixups.Add(new FixUp(propertyFqName, FixUpType.MarkPropertySetAsProtected)); 
                }
            }

        } 

        ///  
        /// Emit the set statements for a property that is a scalar type 
        /// 
        /// The statement collection to add the set statements to. 
        private void EmitScalarTypePropertySetStatements(CodeStatementCollection statements,
            CollectionKind collectionKind)
        {
            Debug.Assert(statements != null, "statments can't be null"); 
            Debug.Assert(((TypeSemantics.IsPrimitiveType(Item.TypeUsage)) || (TypeSemantics.IsCollectionType(Item.TypeUsage)))
                , "Must be a primitive type or collection type property"); 
 
            CodePropertySetValueReferenceExpression valueRef = new CodePropertySetValueReferenceExpression();
            //Since collections are not supported by 
            //the stack, we don't need to do anything special
            //like doing an Attach or Detatch like the way we do for complex types.
            if (collectionKind == CollectionKind.None)
            { 

                PrimitiveType primitiveType = (PrimitiveType)Item.TypeUsage.EdmType; 
 
                // basic pattern
                // this.fieldName = SetValidValue( value ); 
                //
                List parameters = new List();
                parameters.Add(valueRef);
 

                // pattern for non Nullable types (string, byte[]) 
                // 
                // this.fieldName = SetValidVaue( value, nullability );
 
                if (primitiveType.ClrEquivalentType.IsClass)
                {
                    // ref types have an extra boolean parameter to tell if the property is allowed to
                    // be null or not 
                    parameters.Add(new CodePrimitiveExpression(Item.Nullable));
                } 
 
                // now create and add the built statement
                statements.Add( 
                    new CodeAssignStatement(
                            FieldRef,
                            new CodeMethodInvokeExpression(
                                CreateEdmStructuralObjectRef(TypeReference), 
                                Utils.SetValidValueMethodName,
                                parameters.ToArray()))); 
            } 
            else
            { 
                // this.fieldName = value;
                statements.Add(
                    new CodeAssignStatement(
                        FieldRef, valueRef)); 

            } 
        } 

        private CodeExpression GetEnumValue(T value) 
        {
            Type type = typeof(T);
            return new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(TypeReference.ForType(type)), Enum.GetName(type, value));
        } 

 
        ///  
        /// Emit the property set statments to properly set a ComplexType.
        ///  
        /// The collection of statements that the set statements should be added to.
        private void EmitComplexTypePropertySetStatements(CodeStatementCollection statements, CollectionKind collectionKind)
        {
            CodePropertySetValueReferenceExpression valueRef = new CodePropertySetValueReferenceExpression(); 
            //Since collections are not supported by
            //the stack, we don't need to do anything special 
            //like doing an Attach or Detatch like the way we do for complex types. 
            if (collectionKind == CollectionKind.None)
            { 

                // this.fieldName = SetValidValue( this.fieldName, value, _pifieldName);
                statements.Add(
                    new CodeAssignStatement( 
                        FieldRef,
                        new CodeMethodInvokeExpression( 
                                ThisRef, 
                                Utils.SetValidValueMethodName,
                                FieldRef, 
                                valueRef,
                                new CodePrimitiveExpression(PropertyName))));

                // this._complexPropertyInitialized = true; 
                statements.Add(
                    new CodeAssignStatement( 
                        ComplexPropertyInitializedFieldRef, 
                        new CodePrimitiveExpression(true)));
            } 
            else
            {
                // this.fieldName = value;
                statements.Add( 
                    new CodeAssignStatement(
                        FieldRef, valueRef)); 
 
            }
 
        }

        /// 
        /// See if a property names will hide a base class member name 
        /// 
        private bool HidesBaseClassProperty 
        { 
            get
            { 
                StructuralType parentBaseClass = Item.DeclaringType.BaseType as StructuralType;
                if (parentBaseClass != null && parentBaseClass.Members.Contains(PropertyName))
                    return true;
 
                return false;
            } 
        } 

        ///  
        ///
        /// 
        /// 
        ///  
        /// 
        private CodeTypeReference GetType(EdmProperty property, bool getElementType) 
        { 
            PropertyTypeReferences types = default(PropertyTypeReferences);
            EdmType propertyType = property.TypeUsage.EdmType; 

            // Initialize types
            if (Helper.IsPrimitiveType(propertyType))
            { 
                types = new PropertyTypeReferences(TypeReference, (PrimitiveType)propertyType);
            } 
            else if (Helper.IsComplexType(propertyType)) 
            {
                types = new PropertyTypeReferences(TypeReference, (ComplexType)propertyType, Generator); 
            }
            else if (Helper.IsCollectionType(propertyType))
            {
                TypeUsage typeUsage = ((CollectionType)propertyType).TypeUsage; 
                if (Helper.IsPrimitiveType(typeUsage.EdmType))
                { 
                    types = new PropertyTypeReferences(TypeReference, (PrimitiveType)typeUsage.EdmType, GetCollectionKind(property.TypeUsage)); 
                }
                else 
                {
                    Debug.Assert(Helper.IsComplexType(typeUsage.EdmType));
                    types = new PropertyTypeReferences(TypeReference, (ComplexType)typeUsage.EdmType, GetCollectionKind(property.TypeUsage), Generator);
                } 
            }
            else 
            { 
                // shouldn't be able to get here....
                Debug.Fail("Unexpected Property.Type type: " + propertyType.GetType()); 
            }

            // Set types, or retrieve existing types if they have been set in the interim
            // Don't cache Collection types since CollectionKind is really a facet and 
            //it is not part of the key we are using for the dictionary used to cache.
            if (!Helper.IsCollectionType(propertyType)) 
            { 
                Debug.Assert(types.NonNullable != null && types.Nullable != null, "did you forget to set the types variable?");
            } 

            if (property.Nullable)
            {
                return types.Nullable; 
            }
            else 
            { 
                return types.NonNullable;
            } 
        }


        private static CollectionKind GetCollectionKind(TypeUsage usage) 
        {
            Facet collectionFacet; 
            if (usage.Facets.TryGetValue(EdmConstants.CollectionKind, false, out collectionFacet)) 
            {
                return (CollectionKind)collectionFacet.Value; 
            }

            return CollectionKind.None;
        } 

        private string OnChangingPartialMethodName(string propertyName) { return "On" + propertyName + "Changing"; } 
        private string OnChangedPartialMethodName(string propertyName) { return "On" + propertyName + "Changed"; } 

        #endregion 

        #region Private Properties
        /// 
        /// 
        /// 
        private CodeFieldReferenceExpression FieldRef 
        { 
            get
            { 
                if (_fieldRef == null)
                    _fieldRef = new CodeFieldReferenceExpression(ThisRef, FieldName);

                return _fieldRef; 
            }
        } 
        ///  
        ///
        ///  
        private CodeFieldReferenceExpression ComplexPropertyInitializedFieldRef
        {
            get
            { 
                if (_complexPropertyInitializedFieldRef == null)
                    _complexPropertyInitializedFieldRef = new CodeFieldReferenceExpression(ThisRef, ComplexPropertyInitializedFieldName); 
 
                return _complexPropertyInitializedFieldRef;
            } 
        }
        /// 
        ///
        ///  
        private string FieldName
        { 
            get 
            {
                return Utils.FieldNameFromPropName(PropertyName); 
            }
        }
        /// 
        /// 
        /// 
        private string ComplexPropertyInitializedFieldName 
        { 
            get
            { 
                return Utils.ComplexPropertyInitializedNameFromPropName(PropertyName);
            }
        }
 
        internal bool IsKeyProperty
        { 
            get 
            {
                EntityType entity = Item.DeclaringType as EntityType; 
                if (entity != null)
                {
                    return entity.KeyMembers.Contains(Item.Name);
                } 
                return false;
            } 
        } 

        ///  
        ///
        /// 
        internal static bool HasDefault(EdmProperty property)
        { 
            return property.DefaultValue != null;
        } 
 
        /// 
        /// 
        /// 
        private CodeExpression GetDefaultValueExpression(EdmProperty property)
        {
            PrimitiveTypeKind type; 
            object value = property.DefaultValue;
            if (value != null 
                 && Utils.TryGetPrimitiveTypeKind(property.TypeUsage.EdmType, out type)) 
            {
                switch (type) 
                {
                    case PrimitiveTypeKind.Boolean:
                    case PrimitiveTypeKind.Byte:
                    case PrimitiveTypeKind.Int16: 
                    case PrimitiveTypeKind.Int32:
                    case PrimitiveTypeKind.Int64: 
                    case PrimitiveTypeKind.Decimal: 
                    case PrimitiveTypeKind.Single:
                    case PrimitiveTypeKind.Double: 
                    case PrimitiveTypeKind.String:
                        {
                            if (!property.Nullable && value.Equals(TypeSystem.GetDefaultValue(value.GetType())))
                            { 
                                break;
                            } 
                            return new CodePrimitiveExpression(value); 
                        }
                    case PrimitiveTypeKind.Guid: 
                        {
                            if (!property.Nullable && value.Equals(TypeSystem.GetDefaultValue(value.GetType())))
                            {
                                break; 
                            }
                            return GetCodeExpressionFromGuid(value); 
                        } 
                    case PrimitiveTypeKind.DateTime:
                        { 
                            if (!property.Nullable && value.Equals(TypeSystem.GetDefaultValue(value.GetType())))
                            {
                                break;
                            } 
                            return GetCodeExpressionFromDateTimeDefaultValue(value, property);
                        } 
                    case PrimitiveTypeKind.Binary: 
                        {
                            return GetCodeExpressionFromBinary(value); 
                        }
                }
                return null;
            } 

            return null; 
        } 

        ///  
        ///
        /// 
        private CodeExpression GetCodeExpressionFromBinary(object value)
        { 
            byte[] data = (byte[])value;
            CodeExpression[] bytes = new CodeExpression[data.Length]; 
 
            for (int iByte = 0; iByte < data.Length; ++iByte)
            { 
                bytes[iByte] = new CodePrimitiveExpression(data[iByte]);
            }

            return new CodeArrayCreateExpression(TypeReference.ByteArray, bytes); 
        }
 
        ///  
        ///
        ///  
        /// 
        private CodeExpression GetCodeExpressionFromGuid(object value)
        {
            Guid guid = (Guid)value; 
            return new CodeObjectCreateExpression(TypeReference.Guid,
                new CodePrimitiveExpression(guid.ToString("D", CultureInfo.InvariantCulture))); 
        } 

        ///  
        ///
        /// 
        private CodeExpression GetCodeExpressionFromDateTimeDefaultValue(object value, EdmProperty property)
        { 
            DateTime utc = (DateTime)value;
            DateTime dateTime = DateTime.SpecifyKind(utc, DateTimeKind.Unspecified); 
 

            return new CodeObjectCreateExpression(TypeReference.DateTime, new CodePrimitiveExpression(dateTime.Ticks), GetEnumValue(DateTimeKind.Unspecified)); 
        }

        /// 
        /// 
        /// 
        public bool IsVirtualProperty 
        { 
            get
            { 
                return false;
            }
        }
 
        private struct PropertyTypeReferences
        { 
            CodeTypeReference _nonNullable; 
            CodeTypeReference _nullable;
            public PropertyTypeReferences(TypeReference typeReference, PrimitiveType primitiveType) 
                : this(typeReference, primitiveType, CollectionKind.None)
            {
            }
 
            public PropertyTypeReferences(TypeReference typeReference, PrimitiveType primitiveType, CollectionKind collectionKind)
            { 
                Type type = primitiveType.ClrEquivalentType; 
                if (collectionKind == CollectionKind.None)
                { 
                    _nonNullable = typeReference.ForType(type);
                    if (type.IsValueType)
                    {
                        _nullable = typeReference.NullableForType(type); 
                    }
                    else 
                    { 
                        _nullable = typeReference.ForType(type);
                    } 
                }
                else
                {
                    CodeTypeReference primitiveTypeRef = typeReference.ForType(type); 
                    CodeTypeReference collectionType = GetCollectionTypeReference(typeReference, primitiveTypeRef, collectionKind);
                    _nonNullable = collectionType; 
                    _nullable = collectionType; 
                }
            } 

            public PropertyTypeReferences(TypeReference typeReference, ComplexType complexType, CollectionKind collectionKind, ClientApiGenerator generator)
            {
                CodeTypeReference baseType = generator.GetLeastPossibleQualifiedTypeReference(complexType); 
                baseType = GetCollectionTypeReference(typeReference, baseType, collectionKind);
                _nonNullable = baseType; 
                _nullable = baseType; 
            }
 
            private static CodeTypeReference GetCollectionTypeReference(TypeReference typeReference, CodeTypeReference baseType, CollectionKind collectionKind)
            {
                if (collectionKind == CollectionKind.Bag)
                { 
                    baseType = GetCollectionTypeReferenceForBagSemantics(typeReference, baseType);
                } 
                else if (collectionKind == CollectionKind.List) 
                {
                    baseType = GetCollectionTypeReferenceForListSemantics(typeReference, baseType); 
                }
                else
                {
                    Debug.Assert(collectionKind == CollectionKind.None, "Was another CollectionKind value added"); 
                    // nothing more to do for .None
                } 
                return baseType; 
            }
 
            public PropertyTypeReferences(TypeReference typeReference, ComplexType complexType, ClientApiGenerator generator)
                : this(typeReference, complexType, CollectionKind.None, generator)
            {
            } 

            private static CodeTypeReference GetCollectionTypeReferenceForBagSemantics(TypeReference typeReference, CodeTypeReference baseType) 
            { 
                CodeTypeReference typeRef = typeReference.ForType(typeof(System.Collections.Generic.ICollection<>), baseType);
                return typeRef; 
            }

            private static CodeTypeReference GetCollectionTypeReferenceForListSemantics(TypeReference typeReference, CodeTypeReference baseType)
            { 
                CodeTypeReference typeRef = typeReference.ForType(typeof(System.Collections.Generic.IList<>), baseType);
                return typeRef; 
            } 

            public CodeTypeReference NonNullable 
            {
                get { return _nonNullable; }
            }
            public CodeTypeReference Nullable 
            {
                get { return _nullable; } 
            } 
        }
        #endregion 



        // properties from ClassPropertyEmitter 

        public string PropertyFQName 
        { 
            get
            { 
                return Item.DeclaringType.FullName + "." + Item.Name;
            }
        }
 
        public string PropertyName
        { 
            get 
            {
                return EntityPropertyName; 
            }
        }

        private string PropertyClassName 
        {
            get 
            { 
                return Item.DeclaringType.Name;
            } 
        }

        private CodeMemberProperty EmitPropertyDeclaration(MemberAttributes scope, CodeTypeReference propertyType, bool isVirtual,
            bool hidesBaseProperty) 
        {
            Debug.Assert(GetAccessibilityRank(scope) >= 0, "scope should only be an accessibility attribute"); 
 
            CodeMemberProperty memberProperty = new CodeMemberProperty();
            memberProperty.Name = PropertyName; 
            CommentEmitter.EmitSummaryComments(Item, memberProperty.Comments);

            memberProperty.Attributes = scope;
 
            if (!isVirtual)
            { 
                memberProperty.Attributes |= MemberAttributes.Final; 
            }
 
            if (hidesBaseProperty || AncestorClassDefinesName(memberProperty.Name))
            {
                memberProperty.Attributes |= MemberAttributes.New;
            } 

            memberProperty.Type = propertyType; 
 
            return memberProperty;
        } 


        private void DisallowReturnTypeChange(CodeTypeReference baseType, CodeTypeReference newType)
        { 
            if (Helper.IsCollectionType(Item.TypeUsage.EdmType) && GetCollectionKind(Item.TypeUsage) != CollectionKind.None)
            { 
                if (newType == null) 
                {
                    throw EDesignUtil.InvalidOperation(Strings.CannotChangePropertyReturnTypeToNull(Item.Name, Item.DeclaringType.Name)); 
                }

                // you can change the return type of collection properties
                // we don't even need to check 
                return;
            } 
 

            if (!(baseType == null && newType == null) && 
                (
                    (baseType != null && !baseType.Equals(newType)) ||
                    (newType != null && !newType.Equals(baseType))
                ) 
               )
            { 
                throw EDesignUtil.InvalidOperation(Strings.CannotChangePropertyReturnType(Item.Name, Item.DeclaringType.Name)); 
            }
        } 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

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