PageRenderTime 40ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/mcs/class/referencesource/System.Data.Entity.Design/System/Data/EntityModel/Emitters/StructuredTypeEmitter.cs

https://github.com/pruiz/mono
C# | 312 lines | 192 code | 57 blank | 63 comment | 23 complexity | 5074f876befc19c537551391cffbf905 MD5 | raw file
Possible License(s): LGPL-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0
  1. //---------------------------------------------------------------------
  2. // <copyright file="StructuredTypeEmitter.cs" company="Microsoft">
  3. // Copyright (c) Microsoft Corporation. All rights reserved.
  4. // </copyright>
  5. //
  6. // @owner Microsoft
  7. // @backupOwner Microsoft
  8. //---------------------------------------------------------------------
  9. using System;
  10. using System.Collections;
  11. using System.Collections.Generic;
  12. using System.CodeDom;
  13. using System.Data;
  14. using System.Data.EntityModel.SchemaObjectModel;
  15. using Som = System.Data.EntityModel.SchemaObjectModel;
  16. using System.Data.Entity.Design;
  17. using System.Data.Metadata.Edm;
  18. using System.Diagnostics;
  19. using System.Reflection;
  20. using System.Data.Objects.DataClasses;
  21. using System.Data.Entity.Design.Common;
  22. using System.Data.Entity.Design.SsdlGenerator;
  23. namespace System.Data.EntityModel.Emitters
  24. {
  25. /// <summary>
  26. /// Summary description for StructuredTypeEmitter.
  27. /// </summary>
  28. internal abstract class StructuredTypeEmitter : SchemaTypeEmitter
  29. {
  30. #region Public Methods
  31. private bool _usingStandardBaseClass = true;
  32. /// <summary>
  33. ///
  34. /// </summary>
  35. /// <returns></returns>
  36. public override CodeTypeDeclarationCollection EmitApiClass()
  37. {
  38. Validate(); // emitter-specific validation
  39. CodeTypeReference baseType = this.GetBaseType();
  40. // raise the TypeGenerated event
  41. TypeGeneratedEventArgs eventArgs = new TypeGeneratedEventArgs(Item, baseType);
  42. this.Generator.RaiseTypeGeneratedEvent(eventArgs);
  43. // public [abstract] partial class ClassName
  44. CodeTypeDeclaration typeDecl = new CodeTypeDeclaration(Item.Name);
  45. typeDecl.IsPartial = true;
  46. typeDecl.TypeAttributes = System.Reflection.TypeAttributes.Class;
  47. if (Item.Abstract)
  48. {
  49. typeDecl.TypeAttributes |= System.Reflection.TypeAttributes.Abstract;
  50. }
  51. SetTypeVisibility(typeDecl);
  52. EmitTypeAttributes(Item.Name, typeDecl, eventArgs.AdditionalAttributes);
  53. // : baseclass
  54. AssignBaseType(typeDecl, baseType, eventArgs.BaseType);
  55. AddInterfaces(Item.Name, typeDecl, eventArgs.AdditionalInterfaces);
  56. CommentEmitter.EmitSummaryComments(Item, typeDecl.Comments);
  57. // Since abstract types cannot be instantiated, skip the factory method for abstract types
  58. if ( (typeDecl.TypeAttributes & System.Reflection.TypeAttributes.Abstract) == 0)
  59. EmitFactoryMethod(typeDecl);
  60. EmitProperties(typeDecl);
  61. // additional members, if provided by the event subscriber
  62. this.AddMembers(Item.Name, typeDecl, eventArgs.AdditionalMembers);
  63. CodeTypeDeclarationCollection typeDecls = new CodeTypeDeclarationCollection();
  64. typeDecls.Add(typeDecl);
  65. return typeDecls;
  66. }
  67. #endregion
  68. #region Protected Methods
  69. /// <summary>
  70. ///
  71. /// </summary>
  72. /// <returns></returns>
  73. protected virtual CodeTypeReference GetBaseType()
  74. {
  75. if (Item.BaseType == null)
  76. return null;
  77. return Generator.GetLeastPossibleQualifiedTypeReference(Item.BaseType);
  78. }
  79. /// <summary>
  80. ///
  81. /// </summary>
  82. /// <param name="generator"></param>
  83. /// <param name="structuredType"></param>
  84. protected StructuredTypeEmitter(ClientApiGenerator generator, StructuralType structuralType)
  85. : base(generator, structuralType)
  86. {
  87. }
  88. /// <summary>
  89. ///
  90. /// </summary>
  91. /// <param name="typeDecl"></param>
  92. protected override void EmitTypeAttributes(CodeTypeDeclaration typeDecl)
  93. {
  94. Generator.AttributeEmitter.EmitTypeAttributes(this, typeDecl);
  95. base.EmitTypeAttributes(typeDecl);
  96. }
  97. /// <summary>
  98. ///
  99. /// </summary>
  100. /// <param name="typeDecl"></param>
  101. protected virtual void EmitProperties(CodeTypeDeclaration typeDecl)
  102. {
  103. foreach (EdmProperty property in Item.GetDeclaredOnlyMembers<EdmProperty>())
  104. {
  105. PropertyEmitter propertyEmitter = new PropertyEmitter(Generator, property, _usingStandardBaseClass);
  106. propertyEmitter.Emit(typeDecl);
  107. }
  108. }
  109. protected abstract ReadOnlyMetadataCollection<EdmProperty> GetProperties();
  110. /// <summary>
  111. /// Emit static factory method which creates an instance of the class and initializes
  112. /// non-nullable properties (taken as arguments)
  113. /// </summary>
  114. /// <param name="typeDecl"></param>
  115. protected virtual void EmitFactoryMethod(CodeTypeDeclaration typeDecl)
  116. {
  117. // build list of non-nullable properties
  118. ReadOnlyMetadataCollection<EdmProperty> properties = GetProperties();
  119. List<EdmProperty> parameters = new List<EdmProperty>(properties.Count);
  120. foreach (EdmProperty property in properties)
  121. {
  122. bool include = IncludeFieldInFactoryMethod(property);
  123. if (include)
  124. {
  125. parameters.Add(property);
  126. }
  127. }
  128. // if there are no parameters, we don't emit anything (1 is for the null element)
  129. // nor do we emit everything if this is the Ref propertied ctor and the parameter list is the same as the many parametered ctor
  130. if (parameters.Count < 1)
  131. {
  132. return;
  133. }
  134. CodeMemberMethod method = new CodeMemberMethod();
  135. Generator.AttributeEmitter.EmitGeneratedCodeAttribute(method);
  136. CodeTypeReference typeRef = TypeReference.FromString(Item.Name);
  137. UniqueIdentifierService uniqueIdentifierService = new UniqueIdentifierService(Generator.IsLanguageCaseSensitive, name => Utils.FixParameterName(name));
  138. string instanceName = uniqueIdentifierService.AdjustIdentifier(Item.Name);
  139. // public static Class CreateClass(...)
  140. method.Attributes = MemberAttributes.Static|MemberAttributes.Public;
  141. method.Name = "Create" + Item.Name;
  142. if (NavigationPropertyEmitter.IsNameAlreadyAMemberName(Item, method.Name, Generator.LanguageAppropriateStringComparer))
  143. {
  144. Generator.AddError(Strings.GeneratedFactoryMethodNameConflict(method.Name, Item.Name),
  145. ModelBuilderErrorCode.GeneratedFactoryMethodNameConflict,
  146. EdmSchemaErrorSeverity.Error, Item.FullName);
  147. }
  148. method.ReturnType = typeRef;
  149. // output method summary comments
  150. CommentEmitter.EmitSummaryComments(Strings.FactoryMethodSummaryComment(Item.Name), method.Comments);
  151. // Class class = new Class();
  152. CodeVariableDeclarationStatement createNewInstance = new CodeVariableDeclarationStatement(
  153. typeRef, instanceName, new CodeObjectCreateExpression(typeRef));
  154. method.Statements.Add(createNewInstance);
  155. CodeVariableReferenceExpression instanceRef = new CodeVariableReferenceExpression(instanceName);
  156. // iterate over the properties figuring out which need included in the factory method
  157. foreach (EdmProperty property in parameters)
  158. {
  159. // CreateClass( ... , propType propName ...)
  160. PropertyEmitter propertyEmitter = new PropertyEmitter(Generator, property, UsingStandardBaseClass);
  161. CodeTypeReference propertyTypeReference = propertyEmitter.PropertyType;
  162. String parameterName = uniqueIdentifierService.AdjustIdentifier(propertyEmitter.PropertyName);
  163. CodeParameterDeclarationExpression paramDecl = new CodeParameterDeclarationExpression(
  164. propertyTypeReference, parameterName);
  165. CodeArgumentReferenceExpression paramRef = new CodeArgumentReferenceExpression(paramDecl.Name);
  166. method.Parameters.Add(paramDecl);
  167. // add comment describing the parameter
  168. CommentEmitter.EmitParamComments(paramDecl, Strings.FactoryParamCommentGeneral(propertyEmitter.PropertyName), method.Comments);
  169. CodeExpression newPropertyValue;
  170. if (MetadataUtil.IsComplexType(propertyEmitter.Item.TypeUsage.EdmType))
  171. {
  172. List<CodeExpression> complexVerifyParameters = new List<CodeExpression>();
  173. complexVerifyParameters.Add(paramRef);
  174. complexVerifyParameters.Add(new CodePrimitiveExpression(propertyEmitter.PropertyName));
  175. newPropertyValue =
  176. new CodeMethodInvokeExpression(
  177. PropertyEmitter.CreateEdmStructuralObjectRef(TypeReference),
  178. Utils.VerifyComplexObjectIsNotNullName,
  179. complexVerifyParameters.ToArray());
  180. }
  181. else
  182. {
  183. newPropertyValue = paramRef;
  184. }
  185. // Scalar property:
  186. // Property = param;
  187. // Complex property:
  188. // Property = StructuralObject.VerifyComplexObjectIsNotNull(param, propertyName);
  189. method.Statements.Add(new CodeAssignStatement(new CodePropertyReferenceExpression(instanceRef, propertyEmitter.PropertyName), newPropertyValue));
  190. }
  191. // return class;
  192. method.Statements.Add(new CodeMethodReturnStatement(instanceRef));
  193. // actually add the method to the class
  194. typeDecl.Members.Add(method);
  195. }
  196. #endregion
  197. #region Protected Properties
  198. internal new StructuralType Item
  199. {
  200. get
  201. {
  202. return base.Item as StructuralType;
  203. }
  204. }
  205. protected bool UsingStandardBaseClass
  206. {
  207. get { return _usingStandardBaseClass; }
  208. }
  209. #endregion
  210. #region Private Methods
  211. /// <summary>
  212. ///
  213. /// </summary>
  214. /// <param name="property"></param>
  215. /// <returns></returns>
  216. private bool IncludeFieldInFactoryMethod(EdmProperty property)
  217. {
  218. if (property.Nullable)
  219. {
  220. return false;
  221. }
  222. if (PropertyEmitter.HasDefault(property))
  223. {
  224. return false;
  225. }
  226. if ((PropertyEmitter.GetGetterAccessibility(property) != MemberAttributes.Public &&
  227. PropertyEmitter.GetSetterAccessibility(property) != MemberAttributes.Public) ||
  228. // declared in a sub type, but not setter accessbile from this type
  229. (Item != property.DeclaringType && PropertyEmitter.GetSetterAccessibility(property) == MemberAttributes.Private)
  230. )
  231. {
  232. return false;
  233. }
  234. return true;
  235. }
  236. private void AssignBaseType(CodeTypeDeclaration typeDecl,
  237. CodeTypeReference baseType,
  238. CodeTypeReference eventReturnedBaseType)
  239. {
  240. if (eventReturnedBaseType != null && !eventReturnedBaseType.Equals(baseType))
  241. {
  242. _usingStandardBaseClass = false;
  243. typeDecl.BaseTypes.Add(eventReturnedBaseType);
  244. }
  245. else
  246. {
  247. if (baseType != null)
  248. {
  249. typeDecl.BaseTypes.Add(baseType);
  250. }
  251. }
  252. }
  253. #endregion
  254. }
  255. }