PropertyEmitter.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataEntityDesign / Design / System / Data / EntityModel / Emitters / PropertyEmitter.cs / 1305376 / 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();
            Generator.AttributeEmitter.EmitGeneratedCodeAttribute(onChangingDomMethod); 
            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(); 
            Generator.AttributeEmitter.EmitGeneratedCodeAttribute(onChangedDomMethod);
            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);
            Generator.AttributeEmitter.EmitGeneratedCodeAttribute(memberField);
 
            memberField.Attributes = MemberAttributes.Private;
            if (HasDefault(Item)) 
            { 
                memberField.InitExpression = GetDefaultValueExpression(Item);
            } 

            typeDecl.Members.Add(memberField);

            if (MetadataUtil.IsComplexType(Item.TypeUsage.EdmType)) 
            {
                CodeMemberField complexInitField = new CodeMemberField(TypeReference.ForType(typeof(bool)), ComplexPropertyInitializedFieldName); 
                Generator.AttributeEmitter.EmitGeneratedCodeAttribute(complexInitField); 
                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 (MetadataUtil.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 (MetadataUtil.IsPrimitiveType(Item.TypeUsage.EdmType)) 
            {
                EmitScalarTypePropertySetStatements(statements, CollectionKind.None); 
            }
            else if (MetadataUtil.IsComplexType(Item.TypeUsage.EdmType))
            {
                // ComplexTypes have a completely different set pattern: 
                EmitComplexTypePropertySetStatements(statements, CollectionKind.None);
            } 
            else if (MetadataUtil.IsCollectionType(Item.TypeUsage.EdmType)) 
            {
                if (MetadataUtil.IsComplexType(((CollectionType)Item.TypeUsage.EdmType).TypeUsage.EdmType)) 
                {
                    EmitComplexTypePropertySetStatements(statements, GetCollectionKind(Item.TypeUsage));
                }
                else 
                {
                    Debug.Assert(MetadataUtil.IsPrimitiveType(((CollectionType)Item.TypeUsage.EdmType).TypeUsage.EdmType), 
                        "Collections should be of primitive types or complex types"); 
                    EmitScalarTypePropertySetStatements(statements, GetCollectionKind(Item.TypeUsage));
                } 

            }
            else if (MetadataUtil.IsEnumerationType(Item.TypeUsage.EdmType))
            { 
                // 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(((MetadataUtil.IsPrimitiveType(Item.TypeUsage.EdmType)) || (MetadataUtil.IsCollectionType(Item.TypeUsage.EdmType)))
                , "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 (MetadataUtil.IsPrimitiveType(propertyType))
            { 
                types = new PropertyTypeReferences(TypeReference, (PrimitiveType)propertyType);
            }
            else if (MetadataUtil.IsComplexType(propertyType))
            { 
                types = new PropertyTypeReferences(TypeReference, (ComplexType)propertyType, Generator);
            } 
            else if (Helper.IsCollectionType(propertyType)) 
            {
                TypeUsage typeUsage = ((CollectionType)propertyType).TypeUsage; 
                if (MetadataUtil.IsPrimitiveType(typeUsage.EdmType))
                {
                    types = new PropertyTypeReferences(TypeReference, (PrimitiveType)typeUsage.EdmType, GetCollectionKind(property.TypeUsage));
                } 
                else
                { 
                    Debug.Assert(MetadataUtil.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();
            Generator.AttributeEmitter.EmitGeneratedCodeAttribute(onChangingDomMethod); 
            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(); 
            Generator.AttributeEmitter.EmitGeneratedCodeAttribute(onChangedDomMethod);
            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);
            Generator.AttributeEmitter.EmitGeneratedCodeAttribute(memberField);
 
            memberField.Attributes = MemberAttributes.Private;
            if (HasDefault(Item)) 
            { 
                memberField.InitExpression = GetDefaultValueExpression(Item);
            } 

            typeDecl.Members.Add(memberField);

            if (MetadataUtil.IsComplexType(Item.TypeUsage.EdmType)) 
            {
                CodeMemberField complexInitField = new CodeMemberField(TypeReference.ForType(typeof(bool)), ComplexPropertyInitializedFieldName); 
                Generator.AttributeEmitter.EmitGeneratedCodeAttribute(complexInitField); 
                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 (MetadataUtil.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 (MetadataUtil.IsPrimitiveType(Item.TypeUsage.EdmType)) 
            {
                EmitScalarTypePropertySetStatements(statements, CollectionKind.None); 
            }
            else if (MetadataUtil.IsComplexType(Item.TypeUsage.EdmType))
            {
                // ComplexTypes have a completely different set pattern: 
                EmitComplexTypePropertySetStatements(statements, CollectionKind.None);
            } 
            else if (MetadataUtil.IsCollectionType(Item.TypeUsage.EdmType)) 
            {
                if (MetadataUtil.IsComplexType(((CollectionType)Item.TypeUsage.EdmType).TypeUsage.EdmType)) 
                {
                    EmitComplexTypePropertySetStatements(statements, GetCollectionKind(Item.TypeUsage));
                }
                else 
                {
                    Debug.Assert(MetadataUtil.IsPrimitiveType(((CollectionType)Item.TypeUsage.EdmType).TypeUsage.EdmType), 
                        "Collections should be of primitive types or complex types"); 
                    EmitScalarTypePropertySetStatements(statements, GetCollectionKind(Item.TypeUsage));
                } 

            }
            else if (MetadataUtil.IsEnumerationType(Item.TypeUsage.EdmType))
            { 
                // 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(((MetadataUtil.IsPrimitiveType(Item.TypeUsage.EdmType)) || (MetadataUtil.IsCollectionType(Item.TypeUsage.EdmType)))
                , "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 (MetadataUtil.IsPrimitiveType(propertyType))
            { 
                types = new PropertyTypeReferences(TypeReference, (PrimitiveType)propertyType);
            }
            else if (MetadataUtil.IsComplexType(propertyType))
            { 
                types = new PropertyTypeReferences(TypeReference, (ComplexType)propertyType, Generator);
            } 
            else if (Helper.IsCollectionType(propertyType)) 
            {
                TypeUsage typeUsage = ((CollectionType)propertyType).TypeUsage; 
                if (MetadataUtil.IsPrimitiveType(typeUsage.EdmType))
                {
                    types = new PropertyTypeReferences(TypeReference, (PrimitiveType)typeUsage.EdmType, GetCollectionKind(property.TypeUsage));
                } 
                else
                { 
                    Debug.Assert(MetadataUtil.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