Code:
/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / ndp / fx / src / DataWeb / Design / system / Data / EntityModel / Emitters / PropertyEmitter.cs / 1 / PropertyEmitter.cs
//---------------------------------------------------------------------- //// Copyright (c) Microsoft Corporation. All rights reserved. // // // @owner [....] // @backupOwner [....] //--------------------------------------------------------------------- using System.CodeDom; using System.Collections.Generic; using System.Data.Common.Utils; using System.Data.Services.Design; using System.Data.Services.Design.Common; 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; private CodeFieldReferenceExpression _complexPropertyInitializedFieldRef; // statics private const string NestedStoreObjectCollection = "InlineObjectCollection"; private const string DetachFromParentMethodName = "DetachFromParent"; #region Public Methods ////// /// /// /// public PropertyEmitter(ClientApiGenerator generator, EdmProperty property, bool declaringTypeUsesStandardBaseType) : base(generator, property, declaringTypeUsesStandardBaseType) { } ////// Emit the declaration of the property for the class. /// ///The Property declaration pieces of the CodeDom. public CodeMemberProperty EmitPropertyDeclaration(CodeTypeReference propertyReturnType) { MemberAttributes scope = AccessibilityFromGettersAndSetters(Item); CodeMemberProperty memberProperty = EmitPropertyDeclaration(scope, propertyReturnType, IsVirtualProperty, HidesBaseClassProperty); memberProperty.HasSet = true; memberProperty.HasGet = true; return memberProperty; } ////// Main method for Emitting property code. /// /// The CodeDom representation of the type that the property is being added to. protected override void EmitProperty(CodeTypeDeclaration typeDecl) { CodeTypeReference typeRef = PropertyType; // raise the PropertyGenerated event // PropertyGeneratedEventArgs eventArgs = new PropertyGeneratedEventArgs(Item, FieldName, typeRef); this.Generator.RaisePropertyGeneratedEvent(eventArgs); // the event subscriber cannot change the return type of the property // DisallowReturnTypeChange(typeRef, eventArgs.ReturnType); CodeMemberProperty memberProperty = EmitPropertyDeclaration(eventArgs.ReturnType); if (memberProperty == null) { return; } EmitCustomAttributes(memberProperty, eventArgs.AdditionalAttributes); EmitPropertyGetter(memberProperty, eventArgs.AdditionalGetStatements); EmitPropertySetter(memberProperty, eventArgs.AdditionalSetStatements); typeDecl.Members.Add(memberProperty); EmitField(typeDecl, eventArgs.ReturnType); EmitPropertyOnChangePartialMethods(typeDecl, eventArgs.ReturnType); } ////// Emit these methods as "abstract" and fix them up later to be "partial". /// CodeDOM does not support partial methods /// /// private void EmitPropertyOnChangePartialMethods(CodeTypeDeclaration typeDecl, CodeTypeReference returnType) { CodeMemberMethod onChangingDomMethod = new CodeMemberMethod(); onChangingDomMethod.Name = OnChangingPartialMethodName(PropertyName); onChangingDomMethod.ReturnType = new CodeTypeReference(typeof(void)); onChangingDomMethod.Attributes = MemberAttributes.Abstract | MemberAttributes.Public; onChangingDomMethod.Parameters.Add(new CodeParameterDeclarationExpression(returnType, "value")); typeDecl.Members.Add(onChangingDomMethod); CodeMemberMethod onChangedDomMethod = new CodeMemberMethod(); onChangedDomMethod.Name = OnChangedPartialMethodName(PropertyName); onChangedDomMethod.ReturnType = new CodeTypeReference(typeof(void)); onChangedDomMethod.Attributes = MemberAttributes.Abstract | MemberAttributes.Public; typeDecl.Members.Add(onChangedDomMethod); Generator.FixUps.Add(new FixUp(PropertyClassName + "." + OnChangingPartialMethodName(PropertyName), FixUpType.MarkAbstractMethodAsPartial)); Generator.FixUps.Add(new FixUp(PropertyClassName + "." + OnChangedPartialMethodName(PropertyName), FixUpType.MarkAbstractMethodAsPartial)); } private void EmitField(CodeTypeDeclaration typeDecl, CodeTypeReference fieldType) { CodeMemberField memberField = new CodeMemberField(fieldType, FieldName); memberField.Attributes = MemberAttributes.Private; if (HasDefault(Item)) { memberField.InitExpression = GetDefaultValueExpression(Item); } typeDecl.Members.Add(memberField); if (TypeSemantics.IsComplexType(Item.TypeUsage)) { CodeMemberField complexInitField = new CodeMemberField(TypeReference.ForType(typeof(bool)), ComplexPropertyInitializedFieldName); complexInitField.Attributes = MemberAttributes.Private; typeDecl.Members.Add(complexInitField); } } #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, ListadditionalAttributes) { Generator.AttributeEmitter.EmitPropertyAttributes(this, memberProperty, additionalAttributes); } private void EmitPropertyGetter(CodeMemberProperty memberProperty, List additionalGetStatements) { CodeStatementCollection statements = memberProperty.GetStatements; // we need to insert user-specified code before other/existing code, including // the return statement if (additionalGetStatements != null && additionalGetStatements.Count > 0) { try { CodeStatementCollection getStatements = new CodeStatementCollection(); getStatements.AddRange(additionalGetStatements.ToArray()); if (statements != null && statements.Count > 0) { getStatements.AddRange(statements); } statements.Clear(); statements.AddRange(getStatements); } catch (ArgumentNullException e) { Generator.AddError(Strings.InvalidGetStatementSuppliedForProperty(Item.Name), ModelBuilderErrorCode.InvalidGetStatementSuppliedForProperty, EdmSchemaErrorSeverity.Error, e); } } MemberAttributes access = memberProperty.Attributes & MemberAttributes.AccessMask; AddGetterSetterFixUp(Generator.FixUps, PropertyFQName, GetGetterAccessibility(Item), access, true); EmitPropertyGetterBody(statements); } /// /// /// /// private void EmitPropertyGetterBody(CodeStatementCollection statements) { // If the SchemaElement.Type isn't a ComplexType it better be PrimitiveType. if (Helper.IsComplexType(Item.TypeUsage.EdmType)) { //Since Complex Collections are not supported by //the stack, we don't need to do anything special //like doing an Attach or Detatch like the way we do for complex types. if (GetCollectionKind(Item.TypeUsage) == CollectionKind.None) { // if ((_field == null)) && // (_fieldInitialized == false)) // { // _field = new(); // _fieldInitialized = true; // } statements.Add( // if new CodeConditionStatement( new CodeBinaryOperatorExpression( // (_field == null)) EmitExpressionEqualsNull(FieldRef), CodeBinaryOperatorType.BooleanAnd, // (_fieldInitialized != true) new CodeBinaryOperatorExpression( ComplexPropertyInitializedFieldRef, CodeBinaryOperatorType.IdentityInequality, new CodePrimitiveExpression(true) ) ), // { _field = new (); new CodeAssignStatement(FieldRef, new CodeObjectCreateExpression(PropertyType) ), // _fieldInitialized = true; } 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[])) { // if (_field != null) { return _filed.Clone(); } else { return null; } statements.Add( // if new CodeConditionStatement( // (_field == null) * (NOT _field Is Nothing) EmitExpressionDoesNotEqualNull(FieldRef), new CodeStatement[] { // { _field = new (); new CodeMethodReturnStatement( new CodeCastExpression(typeof(byte[]), new CodeMethodInvokeExpression(FieldRef, "Clone") ) ) }, new CodeStatement[] { // return null * return Nothing new CodeMethodReturnStatement( NullExpression ) } ) ); } else { // for everything else just return the field. statements.Add(new CodeMethodReturnStatement(FieldRef)); } } } /// /// /// /// /// Additional statements to emit private void EmitPropertySetter(CodeMemberProperty memberProperty, ListadditionalSetStatements) { 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, ListadditionalSetStatements) { // Invoke the partial method "On[PropertyName]Changing(); statements.Add( new CodeMethodInvokeExpression( ThisRef, OnChangingPartialMethodName(PropertyName), new CodePropertySetValueReferenceExpression())); // 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); } } // this.fieldName = value; statements.Add( new CodeAssignStatement( FieldRef, new CodePropertySetValueReferenceExpression())); if (Helper.IsComplexType(Item.TypeUsage.EdmType)) { if (GetCollectionKind(Item.TypeUsage) == CollectionKind.None) { // this._complexPropertyInitialized = true; statements.Add( new CodeAssignStatement( ComplexPropertyInitializedFieldRef, new CodePrimitiveExpression(true))); } } // 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)); } } } private CodeExpression GetEnumValue(T value) { Type type = typeof(T); return new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(TypeReference.ForType(type)), Enum.GetName(type, value)); } /// /// See if a property names will hide a base class member name /// private bool HidesBaseClassProperty { get { StructuralType parentBaseClass = Item.DeclaringType.BaseType as StructuralType; if (parentBaseClass != null && parentBaseClass.Members.Contains(PropertyName)) return true; return false; } } ////// /// /// /// ///private CodeTypeReference GetType(EdmProperty property, bool getElementType) { PropertyTypeReferences types = default(PropertyTypeReferences); EdmType propertyType = property.TypeUsage.EdmType; // Initialize types if (Helper.IsPrimitiveType(propertyType)) { types = new PropertyTypeReferences(TypeReference, (PrimitiveType)propertyType); } else if (Helper.IsComplexType(propertyType)) { types = new PropertyTypeReferences(TypeReference, (ComplexType)propertyType, Generator); } else if (Helper.IsCollectionType(propertyType)) { TypeUsage typeUsage = ((CollectionType)propertyType).TypeUsage; if (Helper.IsPrimitiveType(typeUsage.EdmType)) { types = new PropertyTypeReferences(TypeReference, (PrimitiveType)typeUsage.EdmType, GetCollectionKind(property.TypeUsage)); } else { Debug.Assert(Helper.IsComplexType(typeUsage.EdmType)); types = new PropertyTypeReferences(TypeReference, (ComplexType)typeUsage.EdmType, GetCollectionKind(property.TypeUsage), Generator); } } else { // shouldn't be able to get here.... Debug.Fail("Unexpected Property.Type type: " + propertyType.GetType()); } // Set types, or retrieve existing types if they have been set in the interim // Don't cache Collection types since CollectionKind is really a facet and //it is not part of the key we are using for the dictionary used to cache. if (!Helper.IsCollectionType(propertyType)) { Debug.Assert(types.NonNullable != null && types.Nullable != null, "did you forget to set the types variable?"); } if (property.Nullable) { return types.Nullable; } else { return types.NonNullable; } } private static CollectionKind GetCollectionKind(TypeUsage usage) { Facet collectionFacet; if (usage.Facets.TryGetValue(EdmConstants.CollectionKind, false, out collectionFacet)) { return (CollectionKind)collectionFacet.Value; } return CollectionKind.None; } private string OnChangingPartialMethodName(string propertyName) { return "On" + propertyName + "Changing"; } private string OnChangedPartialMethodName(string propertyName) { return "On" + propertyName + "Changed"; } #endregion #region Private Properties /// /// /// private CodeFieldReferenceExpression FieldRef { get { if (_fieldRef == null) _fieldRef = new CodeFieldReferenceExpression(ThisRef, FieldName); return _fieldRef; } } ////// /// private CodeFieldReferenceExpression ComplexPropertyInitializedFieldRef { get { if (_complexPropertyInitializedFieldRef == null) _complexPropertyInitializedFieldRef = new CodeFieldReferenceExpression(ThisRef, ComplexPropertyInitializedFieldName); return _complexPropertyInitializedFieldRef; } } ////// /// private string FieldName { get { return Utils.FieldNameFromPropName(PropertyName); } } ////// /// private string ComplexPropertyInitializedFieldName { get { return Utils.ComplexPropertyInitializedNameFromPropName(PropertyName); } } ////// /// internal 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.CodeDom; using System.Collections.Generic; using System.Data.Common.Utils; using System.Data.Services.Design; using System.Data.Services.Design.Common; 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; private CodeFieldReferenceExpression _complexPropertyInitializedFieldRef; // statics private const string NestedStoreObjectCollection = "InlineObjectCollection"; private const string DetachFromParentMethodName = "DetachFromParent"; #region Public Methods ////// /// /// /// public PropertyEmitter(ClientApiGenerator generator, EdmProperty property, bool declaringTypeUsesStandardBaseType) : base(generator, property, declaringTypeUsesStandardBaseType) { } ////// Emit the declaration of the property for the class. /// ///The Property declaration pieces of the CodeDom. public CodeMemberProperty EmitPropertyDeclaration(CodeTypeReference propertyReturnType) { MemberAttributes scope = AccessibilityFromGettersAndSetters(Item); CodeMemberProperty memberProperty = EmitPropertyDeclaration(scope, propertyReturnType, IsVirtualProperty, HidesBaseClassProperty); memberProperty.HasSet = true; memberProperty.HasGet = true; return memberProperty; } ////// Main method for Emitting property code. /// /// The CodeDom representation of the type that the property is being added to. protected override void EmitProperty(CodeTypeDeclaration typeDecl) { CodeTypeReference typeRef = PropertyType; // raise the PropertyGenerated event // PropertyGeneratedEventArgs eventArgs = new PropertyGeneratedEventArgs(Item, FieldName, typeRef); this.Generator.RaisePropertyGeneratedEvent(eventArgs); // the event subscriber cannot change the return type of the property // DisallowReturnTypeChange(typeRef, eventArgs.ReturnType); CodeMemberProperty memberProperty = EmitPropertyDeclaration(eventArgs.ReturnType); if (memberProperty == null) { return; } EmitCustomAttributes(memberProperty, eventArgs.AdditionalAttributes); EmitPropertyGetter(memberProperty, eventArgs.AdditionalGetStatements); EmitPropertySetter(memberProperty, eventArgs.AdditionalSetStatements); typeDecl.Members.Add(memberProperty); EmitField(typeDecl, eventArgs.ReturnType); EmitPropertyOnChangePartialMethods(typeDecl, eventArgs.ReturnType); } ////// Emit these methods as "abstract" and fix them up later to be "partial". /// CodeDOM does not support partial methods /// /// private void EmitPropertyOnChangePartialMethods(CodeTypeDeclaration typeDecl, CodeTypeReference returnType) { CodeMemberMethod onChangingDomMethod = new CodeMemberMethod(); onChangingDomMethod.Name = OnChangingPartialMethodName(PropertyName); onChangingDomMethod.ReturnType = new CodeTypeReference(typeof(void)); onChangingDomMethod.Attributes = MemberAttributes.Abstract | MemberAttributes.Public; onChangingDomMethod.Parameters.Add(new CodeParameterDeclarationExpression(returnType, "value")); typeDecl.Members.Add(onChangingDomMethod); CodeMemberMethod onChangedDomMethod = new CodeMemberMethod(); onChangedDomMethod.Name = OnChangedPartialMethodName(PropertyName); onChangedDomMethod.ReturnType = new CodeTypeReference(typeof(void)); onChangedDomMethod.Attributes = MemberAttributes.Abstract | MemberAttributes.Public; typeDecl.Members.Add(onChangedDomMethod); Generator.FixUps.Add(new FixUp(PropertyClassName + "." + OnChangingPartialMethodName(PropertyName), FixUpType.MarkAbstractMethodAsPartial)); Generator.FixUps.Add(new FixUp(PropertyClassName + "." + OnChangedPartialMethodName(PropertyName), FixUpType.MarkAbstractMethodAsPartial)); } private void EmitField(CodeTypeDeclaration typeDecl, CodeTypeReference fieldType) { CodeMemberField memberField = new CodeMemberField(fieldType, FieldName); memberField.Attributes = MemberAttributes.Private; if (HasDefault(Item)) { memberField.InitExpression = GetDefaultValueExpression(Item); } typeDecl.Members.Add(memberField); if (TypeSemantics.IsComplexType(Item.TypeUsage)) { CodeMemberField complexInitField = new CodeMemberField(TypeReference.ForType(typeof(bool)), ComplexPropertyInitializedFieldName); complexInitField.Attributes = MemberAttributes.Private; typeDecl.Members.Add(complexInitField); } } #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, ListadditionalAttributes) { Generator.AttributeEmitter.EmitPropertyAttributes(this, memberProperty, additionalAttributes); } private void EmitPropertyGetter(CodeMemberProperty memberProperty, List additionalGetStatements) { CodeStatementCollection statements = memberProperty.GetStatements; // we need to insert user-specified code before other/existing code, including // the return statement if (additionalGetStatements != null && additionalGetStatements.Count > 0) { try { CodeStatementCollection getStatements = new CodeStatementCollection(); getStatements.AddRange(additionalGetStatements.ToArray()); if (statements != null && statements.Count > 0) { getStatements.AddRange(statements); } statements.Clear(); statements.AddRange(getStatements); } catch (ArgumentNullException e) { Generator.AddError(Strings.InvalidGetStatementSuppliedForProperty(Item.Name), ModelBuilderErrorCode.InvalidGetStatementSuppliedForProperty, EdmSchemaErrorSeverity.Error, e); } } MemberAttributes access = memberProperty.Attributes & MemberAttributes.AccessMask; AddGetterSetterFixUp(Generator.FixUps, PropertyFQName, GetGetterAccessibility(Item), access, true); EmitPropertyGetterBody(statements); } /// /// /// /// private void EmitPropertyGetterBody(CodeStatementCollection statements) { // If the SchemaElement.Type isn't a ComplexType it better be PrimitiveType. if (Helper.IsComplexType(Item.TypeUsage.EdmType)) { //Since Complex Collections are not supported by //the stack, we don't need to do anything special //like doing an Attach or Detatch like the way we do for complex types. if (GetCollectionKind(Item.TypeUsage) == CollectionKind.None) { // if ((_field == null)) && // (_fieldInitialized == false)) // { // _field = new(); // _fieldInitialized = true; // } statements.Add( // if new CodeConditionStatement( new CodeBinaryOperatorExpression( // (_field == null)) EmitExpressionEqualsNull(FieldRef), CodeBinaryOperatorType.BooleanAnd, // (_fieldInitialized != true) new CodeBinaryOperatorExpression( ComplexPropertyInitializedFieldRef, CodeBinaryOperatorType.IdentityInequality, new CodePrimitiveExpression(true) ) ), // { _field = new (); new CodeAssignStatement(FieldRef, new CodeObjectCreateExpression(PropertyType) ), // _fieldInitialized = true; } 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[])) { // if (_field != null) { return _filed.Clone(); } else { return null; } statements.Add( // if new CodeConditionStatement( // (_field == null) * (NOT _field Is Nothing) EmitExpressionDoesNotEqualNull(FieldRef), new CodeStatement[] { // { _field = new (); new CodeMethodReturnStatement( new CodeCastExpression(typeof(byte[]), new CodeMethodInvokeExpression(FieldRef, "Clone") ) ) }, new CodeStatement[] { // return null * return Nothing new CodeMethodReturnStatement( NullExpression ) } ) ); } else { // for everything else just return the field. statements.Add(new CodeMethodReturnStatement(FieldRef)); } } } /// /// /// /// /// Additional statements to emit private void EmitPropertySetter(CodeMemberProperty memberProperty, ListadditionalSetStatements) { 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, ListadditionalSetStatements) { // Invoke the partial method "On[PropertyName]Changing(); statements.Add( new CodeMethodInvokeExpression( ThisRef, OnChangingPartialMethodName(PropertyName), new CodePropertySetValueReferenceExpression())); // 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); } } // this.fieldName = value; statements.Add( new CodeAssignStatement( FieldRef, new CodePropertySetValueReferenceExpression())); if (Helper.IsComplexType(Item.TypeUsage.EdmType)) { if (GetCollectionKind(Item.TypeUsage) == CollectionKind.None) { // this._complexPropertyInitialized = true; statements.Add( new CodeAssignStatement( ComplexPropertyInitializedFieldRef, new CodePrimitiveExpression(true))); } } // 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)); } } } private CodeExpression GetEnumValue(T value) { Type type = typeof(T); return new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(TypeReference.ForType(type)), Enum.GetName(type, value)); } /// /// See if a property names will hide a base class member name /// private bool HidesBaseClassProperty { get { StructuralType parentBaseClass = Item.DeclaringType.BaseType as StructuralType; if (parentBaseClass != null && parentBaseClass.Members.Contains(PropertyName)) return true; return false; } } ////// /// /// /// ///private CodeTypeReference GetType(EdmProperty property, bool getElementType) { PropertyTypeReferences types = default(PropertyTypeReferences); EdmType propertyType = property.TypeUsage.EdmType; // Initialize types if (Helper.IsPrimitiveType(propertyType)) { types = new PropertyTypeReferences(TypeReference, (PrimitiveType)propertyType); } else if (Helper.IsComplexType(propertyType)) { types = new PropertyTypeReferences(TypeReference, (ComplexType)propertyType, Generator); } else if (Helper.IsCollectionType(propertyType)) { TypeUsage typeUsage = ((CollectionType)propertyType).TypeUsage; if (Helper.IsPrimitiveType(typeUsage.EdmType)) { types = new PropertyTypeReferences(TypeReference, (PrimitiveType)typeUsage.EdmType, GetCollectionKind(property.TypeUsage)); } else { Debug.Assert(Helper.IsComplexType(typeUsage.EdmType)); types = new PropertyTypeReferences(TypeReference, (ComplexType)typeUsage.EdmType, GetCollectionKind(property.TypeUsage), Generator); } } else { // shouldn't be able to get here.... Debug.Fail("Unexpected Property.Type type: " + propertyType.GetType()); } // Set types, or retrieve existing types if they have been set in the interim // Don't cache Collection types since CollectionKind is really a facet and //it is not part of the key we are using for the dictionary used to cache. if (!Helper.IsCollectionType(propertyType)) { Debug.Assert(types.NonNullable != null && types.Nullable != null, "did you forget to set the types variable?"); } if (property.Nullable) { return types.Nullable; } else { return types.NonNullable; } } private static CollectionKind GetCollectionKind(TypeUsage usage) { Facet collectionFacet; if (usage.Facets.TryGetValue(EdmConstants.CollectionKind, false, out collectionFacet)) { return (CollectionKind)collectionFacet.Value; } return CollectionKind.None; } private string OnChangingPartialMethodName(string propertyName) { return "On" + propertyName + "Changing"; } private string OnChangedPartialMethodName(string propertyName) { return "On" + propertyName + "Changed"; } #endregion #region Private Properties /// /// /// private CodeFieldReferenceExpression FieldRef { get { if (_fieldRef == null) _fieldRef = new CodeFieldReferenceExpression(ThisRef, FieldName); return _fieldRef; } } ////// /// private CodeFieldReferenceExpression ComplexPropertyInitializedFieldRef { get { if (_complexPropertyInitializedFieldRef == null) _complexPropertyInitializedFieldRef = new CodeFieldReferenceExpression(ThisRef, ComplexPropertyInitializedFieldName); return _complexPropertyInitializedFieldRef; } } ////// /// private string FieldName { get { return Utils.FieldNameFromPropName(PropertyName); } } ////// /// private string ComplexPropertyInitializedFieldName { get { return Utils.ComplexPropertyInitializedNameFromPropName(PropertyName); } } ////// /// internal 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

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- PersonalizationProviderHelper.cs
- HttpModulesSection.cs
- FormViewDeletedEventArgs.cs
- ObjectDataProvider.cs
- BamlBinaryWriter.cs
- ReadOnlyMetadataCollection.cs
- ToolStripSystemRenderer.cs
- Int64AnimationUsingKeyFrames.cs
- ViewgenContext.cs
- DayRenderEvent.cs
- ThicknessAnimationUsingKeyFrames.cs
- ControlValuePropertyAttribute.cs
- ParallelRangeManager.cs
- SafeLibraryHandle.cs
- BindMarkupExtensionSerializer.cs
- SQLDecimal.cs
- Certificate.cs
- DataObjectAttribute.cs
- SiteMapNodeItemEventArgs.cs
- BrowserDefinitionCollection.cs
- BaseDataList.cs
- Lease.cs
- AccessibleObject.cs
- TCPClient.cs
- RuntimeHelpers.cs
- COM2PropertyDescriptor.cs
- Bitmap.cs
- WindowsListViewItem.cs
- VectorValueSerializer.cs
- DesignerWebPartChrome.cs
- DownloadProgressEventArgs.cs
- BindingExpression.cs
- XmlNode.cs
- UnmanagedMarshal.cs
- DataTable.cs
- CodeVariableDeclarationStatement.cs
- ColorKeyFrameCollection.cs
- _HeaderInfoTable.cs
- CacheHelper.cs
- NativeMethods.cs
- InternalConfigHost.cs
- Preprocessor.cs
- CursorConverter.cs
- MD5HashHelper.cs
- regiisutil.cs
- ConfigUtil.cs
- RuntimeResourceSet.cs
- PrintController.cs
- IFlowDocumentViewer.cs
- MenuItemCollection.cs
- RsaSecurityKey.cs
- CssStyleCollection.cs
- ImageDrawing.cs
- _Win32.cs
- FlowDocumentPageViewerAutomationPeer.cs
- Zone.cs
- DataBinding.cs
- PageThemeParser.cs
- ValidationEventArgs.cs
- AddInEnvironment.cs
- TraceContext.cs
- EmbeddedObject.cs
- WindowsSlider.cs
- ViewBase.cs
- ColumnMapProcessor.cs
- MappingException.cs
- DrawingGroup.cs
- SrgsOneOf.cs
- ColumnWidthChangingEvent.cs
- PackagePartCollection.cs
- RootProfilePropertySettingsCollection.cs
- XMLSchema.cs
- FieldTemplateUserControl.cs
- OleDbConnectionPoolGroupProviderInfo.cs
- BlurBitmapEffect.cs
- ProfilePropertyMetadata.cs
- WebZone.cs
- SqlColumnizer.cs
- ListViewSelectEventArgs.cs
- WaitHandle.cs
- DataViewSettingCollection.cs
- FileEnumerator.cs
- IPGlobalProperties.cs
- Size.cs
- AssemblyAttributesGoHere.cs
- HttpResponse.cs
- ChildTable.cs
- httpapplicationstate.cs
- ZipIOExtraFieldPaddingElement.cs
- SoapFormatter.cs
- StringAnimationBase.cs
- columnmapkeybuilder.cs
- XPathNavigator.cs
- XmlSchemaFacet.cs
- DesignerActionItemCollection.cs
- ExtensionWindow.cs
- EasingFunctionBase.cs
- HttpInputStream.cs
- GridItem.cs
- EventDescriptor.cs