//--------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // // // @owner Microsoft // @backupOwner Microsoft //--------------------------------------------------------------------- using System.CodeDom; using System.Collections.Generic; using System.Data.Entity.Design; using System.Data.Entity.Design.Common; using System.Data.Entity.Design.SsdlGenerator; using System.Data.Metadata.Edm; using System.Data.Objects.ELinq; using System.Diagnostics; using System.Globalization; 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)) { if (!property.Nullable && value.Equals(TypeSystem.GetDefaultValue(value.GetType()))) { return null; } 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: { return new CodePrimitiveExpression(value); } case PrimitiveTypeKind.Guid: { return GetCodeExpressionFromGuid(value); } case PrimitiveTypeKind.DateTime: { return GetCodeExpressionFromDateTimeDefaultValue(value, property); } case PrimitiveTypeKind.DateTimeOffset: { return GetCodeExpressionFromDateTimeOffsetDefaultValue(value, property); } case PrimitiveTypeKind.Time: { return GetCodeExpressionFromTimeSpanDefaultValue(value, property); } case PrimitiveTypeKind.Binary: { return GetCodeExpressionFromBinary(value); } default: Debug.Fail("Unsupported property type:" + type.ToString()); break; } 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)); } private CodeExpression GetCodeExpressionFromDateTimeOffsetDefaultValue(object value, EdmProperty property) { DateTimeOffset dateTimeOffset = (DateTimeOffset)value; return new CodeObjectCreateExpression(TypeReference.DateTimeOffset, new CodePrimitiveExpression(dateTimeOffset.Ticks), new CodeObjectCreateExpression(TypeReference.TimeSpan, new CodePrimitiveExpression(dateTimeOffset.Offset.Ticks))); } private CodeExpression GetCodeExpressionFromTimeSpanDefaultValue(object value, EdmProperty property) { TimeSpan timeSpan = (TimeSpan)value; return new CodeObjectCreateExpression(TypeReference.TimeSpan, new CodePrimitiveExpression(timeSpan.Ticks)); } 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)); } } } }