XmlCodeExporter.cs 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844
  1. //------------------------------------------------------------------------------
  2. // <copyright file="XmlCodeExporter.cs" company="Microsoft">
  3. // Copyright (c) Microsoft Corporation. All rights reserved.
  4. // </copyright>
  5. // <owner current="true" primary="true">Microsoft</owner>
  6. //------------------------------------------------------------------------------
  7. namespace System.Xml.Serialization {
  8. using System;
  9. using System.Collections;
  10. using System.IO;
  11. using System.ComponentModel;
  12. using System.Xml.Schema;
  13. using System.CodeDom;
  14. using System.CodeDom.Compiler;
  15. using System.Reflection;
  16. using System.Globalization;
  17. using System.Diagnostics;
  18. using System.Security.Permissions;
  19. using System.Xml.Serialization.Advanced;
  20. /// <include file='doc\XmlCodeExporter.uex' path='docs/doc[@for="XmlCodeExporter"]/*' />
  21. ///<internalonly/>
  22. /// <devdoc>
  23. /// <para>[To be supplied.]</para>
  24. /// </devdoc>
  25. public class XmlCodeExporter : CodeExporter {
  26. /// <include file='doc\XmlCodeExporter.uex' path='docs/doc[@for="XmlCodeExporter.XmlCodeExporter"]/*' />
  27. /// <devdoc>
  28. /// <para>[To be supplied.]</para>
  29. /// </devdoc>
  30. public XmlCodeExporter(CodeNamespace codeNamespace) : base(codeNamespace, null, null, CodeGenerationOptions.GenerateProperties, null) {}
  31. /// <include file='doc\XmlCodeExporter.uex' path='docs/doc[@for="XmlCodeExporter.XmlCodeExporter1"]/*' />
  32. /// <devdoc>
  33. /// <para>[To be supplied.]</para>
  34. /// </devdoc>
  35. public XmlCodeExporter(CodeNamespace codeNamespace, CodeCompileUnit codeCompileUnit) : base(codeNamespace, codeCompileUnit, null, CodeGenerationOptions.GenerateProperties, null) {}
  36. /// <include file='doc\XmlCodeExporter.uex' path='docs/doc[@for="XmlCodeExporter.XmlCodeExporter2"]/*' />
  37. /// <devdoc>
  38. /// <para>[To be supplied.]</para>
  39. /// </devdoc>
  40. public XmlCodeExporter(CodeNamespace codeNamespace, CodeCompileUnit codeCompileUnit, CodeGenerationOptions options)
  41. : base(codeNamespace, codeCompileUnit, null, options, null) {}
  42. /// <include file='doc\XmlCodeExporter.uex' path='docs/doc[@for="XmlCodeExporter.XmlCodeExporter3"]/*' />
  43. /// <devdoc>
  44. /// <para>[To be supplied.]</para>
  45. /// </devdoc>
  46. public XmlCodeExporter(CodeNamespace codeNamespace, CodeCompileUnit codeCompileUnit, CodeGenerationOptions options, Hashtable mappings)
  47. : base(codeNamespace, codeCompileUnit, null, options, mappings) {}
  48. /// <include file='doc\XmlCodeExporter.uex' path='docs/doc[@for="XmlCodeExporter.XmlCodeExporter4"]/*' />
  49. /// <devdoc>
  50. /// <para>[To be supplied.]</para>
  51. /// </devdoc>
  52. public XmlCodeExporter(CodeNamespace codeNamespace, CodeCompileUnit codeCompileUnit, CodeDomProvider codeProvider, CodeGenerationOptions options, Hashtable mappings)
  53. : base(codeNamespace, codeCompileUnit, codeProvider, options, mappings) {}
  54. /// <include file='doc\XmlCodeExporter.uex' path='docs/doc[@for="XmlCodeExporter.ExportTypeMapping"]/*' />
  55. /// <devdoc>
  56. /// <para>[To be supplied.]</para>
  57. /// </devdoc>
  58. public void ExportTypeMapping(XmlTypeMapping xmlTypeMapping) {
  59. xmlTypeMapping.CheckShallow();
  60. CheckScope(xmlTypeMapping.Scope);
  61. if (xmlTypeMapping.Accessor.Any) throw new InvalidOperationException(Res.GetString(Res.XmlIllegalWildcard));
  62. ExportElement(xmlTypeMapping.Accessor);
  63. }
  64. /// <include file='doc\XmlCodeExporter.uex' path='docs/doc[@for="XmlCodeExporter.ExportMembersMapping"]/*' />
  65. /// <devdoc>
  66. /// <para>[To be supplied.]</para>
  67. /// </devdoc>
  68. public void ExportMembersMapping(XmlMembersMapping xmlMembersMapping) {
  69. xmlMembersMapping.CheckShallow();
  70. CheckScope(xmlMembersMapping.Scope);
  71. for (int i = 0; i < xmlMembersMapping.Count; i++) {
  72. AccessorMapping mapping = xmlMembersMapping[i].Mapping;
  73. if (mapping.Xmlns == null) {
  74. if (mapping.Attribute != null) {
  75. ExportType(mapping.Attribute.Mapping, Accessor.UnescapeName(mapping.Attribute.Name), mapping.Attribute.Namespace, null, false);
  76. }
  77. if (mapping.Elements != null) {
  78. for (int j = 0; j < mapping.Elements.Length; j++) {
  79. ElementAccessor element = mapping.Elements[j];
  80. ExportType(element.Mapping, Accessor.UnescapeName(element.Name), element.Namespace, null, false);
  81. }
  82. }
  83. if (mapping.Text != null) {
  84. ExportType(mapping.Text.Mapping, Accessor.UnescapeName(mapping.Text.Name), mapping.Text.Namespace, null, false);
  85. }
  86. }
  87. }
  88. }
  89. void ExportElement(ElementAccessor element) {
  90. ExportType(element.Mapping, Accessor.UnescapeName(element.Name), element.Namespace, element, true);
  91. }
  92. void ExportType(TypeMapping mapping, string ns) {
  93. ExportType(mapping, null, ns, null, true);
  94. }
  95. void ExportType(TypeMapping mapping, string name, string ns, ElementAccessor rootElement, bool checkReference) {
  96. if (mapping.IsReference && mapping.Namespace != Soap.Encoding)
  97. return;
  98. if (mapping is StructMapping && checkReference && ((StructMapping)mapping).ReferencedByTopLevelElement && rootElement == null)
  99. return;
  100. if (mapping is ArrayMapping && rootElement != null && rootElement.IsTopLevelInSchema && ((ArrayMapping)mapping).TopLevelMapping != null) {
  101. mapping = ((ArrayMapping)mapping).TopLevelMapping;
  102. }
  103. CodeTypeDeclaration codeClass = null;
  104. if (ExportedMappings[mapping] == null) {
  105. ExportedMappings.Add(mapping, mapping);
  106. if (mapping.TypeDesc.IsMappedType) {
  107. codeClass = mapping.TypeDesc.ExtendedType.ExportTypeDefinition(CodeNamespace, CodeCompileUnit);
  108. }
  109. else if (mapping is EnumMapping) {
  110. codeClass = ExportEnum((EnumMapping)mapping, typeof(XmlEnumAttribute));
  111. }
  112. else if (mapping is StructMapping) {
  113. codeClass = ExportStruct((StructMapping)mapping);
  114. }
  115. else if (mapping is ArrayMapping) {
  116. EnsureTypesExported(((ArrayMapping)mapping).Elements, ns);
  117. }
  118. if (codeClass != null) {
  119. if (!mapping.TypeDesc.IsMappedType) {
  120. // Add [GeneratedCodeAttribute(Tool=.., Version=..)]
  121. codeClass.CustomAttributes.Add(GeneratedCodeAttribute);
  122. // Add [SerializableAttribute]
  123. codeClass.CustomAttributes.Add(new CodeAttributeDeclaration(typeof(SerializableAttribute).FullName));
  124. if (!codeClass.IsEnum) {
  125. // Add [DebuggerStepThrough]
  126. codeClass.CustomAttributes.Add(new CodeAttributeDeclaration(typeof(DebuggerStepThroughAttribute).FullName));
  127. // Add [DesignerCategory("code")]
  128. codeClass.CustomAttributes.Add(new CodeAttributeDeclaration(typeof(DesignerCategoryAttribute).FullName, new CodeAttributeArgument[] {new CodeAttributeArgument(new CodePrimitiveExpression("code"))}));
  129. }
  130. AddTypeMetadata(codeClass.CustomAttributes, typeof(XmlTypeAttribute), mapping.TypeDesc.Name, Accessor.UnescapeName(mapping.TypeName), mapping.Namespace, mapping.IncludeInSchema);
  131. }
  132. else if (FindAttributeDeclaration(typeof(GeneratedCodeAttribute), codeClass.CustomAttributes) == null) {
  133. // Add [GeneratedCodeAttribute(Tool=.., Version=..)]
  134. codeClass.CustomAttributes.Add(GeneratedCodeAttribute);
  135. }
  136. ExportedClasses.Add(mapping, codeClass);
  137. }
  138. }
  139. else
  140. codeClass = (CodeTypeDeclaration)ExportedClasses[mapping];
  141. if (codeClass != null && rootElement != null)
  142. AddRootMetadata(codeClass.CustomAttributes, mapping, name, ns, rootElement);
  143. }
  144. void AddRootMetadata(CodeAttributeDeclarationCollection metadata, TypeMapping typeMapping, string name, string ns, ElementAccessor rootElement) {
  145. string rootAttrName = typeof(XmlRootAttribute).FullName;
  146. // check that we haven't already added a root attribute since we can only add one
  147. foreach (CodeAttributeDeclaration attr in metadata) {
  148. if (attr.Name == rootAttrName) return;
  149. }
  150. CodeAttributeDeclaration attribute = new CodeAttributeDeclaration(rootAttrName);
  151. if (typeMapping.TypeDesc.Name != name) {
  152. attribute.Arguments.Add(new CodeAttributeArgument(new CodePrimitiveExpression(name)));
  153. }
  154. if (ns != null) {
  155. attribute.Arguments.Add(new CodeAttributeArgument("Namespace", new CodePrimitiveExpression(ns)));
  156. }
  157. if (typeMapping.TypeDesc != null && typeMapping.TypeDesc.IsAmbiguousDataType) {
  158. attribute.Arguments.Add(new CodeAttributeArgument("DataType", new CodePrimitiveExpression(typeMapping.TypeDesc.DataType.Name)));
  159. }
  160. if ((object)(rootElement.IsNullable) != null) {
  161. attribute.Arguments.Add(new CodeAttributeArgument("IsNullable", new CodePrimitiveExpression((bool)rootElement.IsNullable)));
  162. }
  163. metadata.Add(attribute);
  164. }
  165. CodeAttributeArgument[] GetDefaultValueArguments(PrimitiveMapping mapping, object value, out CodeExpression initExpression) {
  166. initExpression = null;
  167. if (value == null) return null;
  168. CodeExpression valueExpression = null;
  169. CodeExpression typeofValue = null;
  170. Type type = value.GetType();
  171. CodeAttributeArgument[] arguments = null;
  172. if (mapping is EnumMapping) {
  173. #if DEBUG
  174. // use exception in the place of Debug.Assert to avoid throwing asserts from a server process such as aspnet_ewp.exe
  175. if (value.GetType() != typeof(string)) throw new InvalidOperationException(Res.GetString(Res.XmlInternalErrorDetails, "Invalid enumeration type " + value.GetType().Name));
  176. #endif
  177. if (((EnumMapping)mapping).IsFlags) {
  178. string[] values = ((string)value).Split(null);
  179. for (int i = 0; i < values.Length; i++) {
  180. if (values[i].Length == 0) continue;
  181. CodeExpression enumRef = new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(mapping.TypeDesc.FullName), values[i]);
  182. if (valueExpression != null)
  183. valueExpression = new CodeBinaryOperatorExpression(valueExpression, CodeBinaryOperatorType.BitwiseOr, enumRef);
  184. else
  185. valueExpression = enumRef;
  186. }
  187. }
  188. else {
  189. valueExpression = new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(mapping.TypeDesc.FullName), (string)value);
  190. }
  191. initExpression = valueExpression;
  192. arguments = new CodeAttributeArgument[] {new CodeAttributeArgument(valueExpression)};
  193. }
  194. else if (type == typeof(bool) ||
  195. type == typeof(Int32) ||
  196. type == typeof(string) ||
  197. type == typeof(double)) {
  198. initExpression = valueExpression = new CodePrimitiveExpression(value);
  199. arguments = new CodeAttributeArgument[] {new CodeAttributeArgument(valueExpression)};
  200. }
  201. else if (type == typeof(Int16) ||
  202. type == typeof(Int64) ||
  203. type == typeof(float) ||
  204. type == typeof(byte) ||
  205. type == typeof(decimal)) {
  206. valueExpression = new CodePrimitiveExpression(Convert.ToString(value, NumberFormatInfo.InvariantInfo));
  207. typeofValue = new CodeTypeOfExpression(type.FullName);
  208. arguments = new CodeAttributeArgument[] {new CodeAttributeArgument(typeofValue), new CodeAttributeArgument(valueExpression)};
  209. initExpression = new CodeCastExpression(type.FullName, new CodePrimitiveExpression(value));
  210. }
  211. else if (type == typeof(sbyte) ||
  212. type == typeof(UInt16) ||
  213. type == typeof(UInt32) ||
  214. type == typeof(UInt64)) {
  215. // need to promote the non-CLS complient types
  216. value = PromoteType(type, value);
  217. valueExpression = new CodePrimitiveExpression(Convert.ToString(value, NumberFormatInfo.InvariantInfo));
  218. typeofValue = new CodeTypeOfExpression(type.FullName);
  219. arguments = new CodeAttributeArgument[] {new CodeAttributeArgument(typeofValue), new CodeAttributeArgument(valueExpression)};
  220. initExpression = new CodeCastExpression(type.FullName, new CodePrimitiveExpression(value));
  221. }
  222. else if (type == typeof(DateTime)) {
  223. DateTime dt = (DateTime)value;
  224. string dtString;
  225. long ticks;
  226. if (mapping.TypeDesc.FormatterName == "Date") {
  227. dtString = XmlCustomFormatter.FromDate(dt);
  228. ticks = (new DateTime(dt.Year, dt.Month, dt.Day)).Ticks;
  229. }
  230. else if (mapping.TypeDesc.FormatterName == "Time") {
  231. dtString = XmlCustomFormatter.FromDateTime(dt);
  232. ticks = dt.Ticks;
  233. }
  234. else {
  235. dtString = XmlCustomFormatter.FromDateTime(dt);
  236. ticks = dt.Ticks;
  237. }
  238. valueExpression = new CodePrimitiveExpression(dtString);
  239. typeofValue = new CodeTypeOfExpression(type.FullName);
  240. arguments = new CodeAttributeArgument[] {new CodeAttributeArgument(typeofValue), new CodeAttributeArgument(valueExpression)};
  241. initExpression = new CodeObjectCreateExpression(new CodeTypeReference(typeof(DateTime)), new CodeExpression[] {new CodePrimitiveExpression(ticks)});
  242. }
  243. else if (type == typeof(Guid)) {
  244. valueExpression = new CodePrimitiveExpression(Convert.ToString(value, NumberFormatInfo.InvariantInfo));
  245. typeofValue = new CodeTypeOfExpression(type.FullName);
  246. arguments = new CodeAttributeArgument[] {new CodeAttributeArgument(typeofValue), new CodeAttributeArgument(valueExpression)};
  247. initExpression = new CodeObjectCreateExpression(new CodeTypeReference(typeof(Guid)), new CodeExpression[] {valueExpression});
  248. }
  249. if (mapping.TypeDesc.FullName != type.ToString() && !(mapping is EnumMapping)) {
  250. // generate cast
  251. initExpression = new CodeCastExpression(mapping.TypeDesc.FullName, initExpression);
  252. }
  253. return arguments;
  254. }
  255. object ImportDefault(TypeMapping mapping, string defaultValue) {
  256. if (defaultValue == null)
  257. return null;
  258. if (mapping.IsList) {
  259. string[] vals = defaultValue.Trim().Split(null);
  260. // count all non-zero length values;
  261. int count = 0;
  262. for (int i = 0; i < vals.Length; i++) {
  263. if (vals[i] != null && vals[i].Length > 0) count++;
  264. }
  265. object[] values = new object[count];
  266. count = 0;
  267. for (int i = 0; i < vals.Length; i++) {
  268. if (vals[i] != null && vals[i].Length > 0) {
  269. values[count++] = ImportDefaultValue(mapping, vals[i]);
  270. }
  271. }
  272. return values;
  273. }
  274. return ImportDefaultValue(mapping, defaultValue);
  275. }
  276. object ImportDefaultValue(TypeMapping mapping, string defaultValue) {
  277. if (defaultValue == null)
  278. return null;
  279. if (!(mapping is PrimitiveMapping))
  280. return DBNull.Value;
  281. if (mapping is EnumMapping) {
  282. EnumMapping em = (EnumMapping)mapping;
  283. ConstantMapping[] c = em.Constants;
  284. if (em.IsFlags) {
  285. Hashtable values = new Hashtable();
  286. string[] names = new string[c.Length];
  287. long[] ids = new long[c.Length];
  288. for (int i = 0; i < c.Length; i++) {
  289. ids[i] = em.IsFlags ? 1L << i : (long)i;
  290. names[i] = c[i].Name;
  291. values.Add(c[i].Name, ids[i]);
  292. }
  293. // this validates the values
  294. long val = XmlCustomFormatter.ToEnum(defaultValue, values, em.TypeName, true);
  295. return XmlCustomFormatter.FromEnum(val, names, ids, em.TypeDesc.FullName);
  296. }
  297. else {
  298. for (int i = 0; i < c.Length; i++) {
  299. if (c[i].XmlName == defaultValue)
  300. return c[i].Name;
  301. }
  302. }
  303. throw new InvalidOperationException(Res.GetString(Res.XmlInvalidDefaultValue, defaultValue, em.TypeDesc.FullName));
  304. }
  305. // Primitive mapping
  306. PrimitiveMapping pm = (PrimitiveMapping)mapping;
  307. if (!pm.TypeDesc.HasCustomFormatter) {
  308. if (pm.TypeDesc.FormatterName == "String")
  309. return defaultValue;
  310. if (pm.TypeDesc.FormatterName == "DateTime")
  311. return XmlCustomFormatter.ToDateTime(defaultValue);
  312. Type formatter = typeof(XmlConvert);
  313. MethodInfo format = formatter.GetMethod("To" + pm.TypeDesc.FormatterName, new Type[] {typeof(string)});
  314. if (format != null) {
  315. return format.Invoke(formatter, new Object[] {defaultValue});
  316. }
  317. #if DEBUG
  318. Debug.WriteLineIf(DiagnosticsSwitches.XmlSerialization.TraceVerbose, "XmlSerialization::Failed to GetMethod " + formatter.Name + ".To" + pm.TypeDesc.FormatterName);
  319. #endif
  320. }
  321. else {
  322. if (pm.TypeDesc.HasDefaultSupport) {
  323. return XmlCustomFormatter.ToDefaultValue(defaultValue, pm.TypeDesc.FormatterName);
  324. }
  325. }
  326. return DBNull.Value;
  327. }
  328. void AddDefaultValueAttribute(CodeMemberField field, CodeAttributeDeclarationCollection metadata, object defaultValue, TypeMapping mapping, CodeCommentStatementCollection comments, TypeDesc memberTypeDesc, Accessor accessor, CodeConstructor ctor) {
  329. string attributeName = accessor.IsFixed ? "fixed" : "default";
  330. if (!memberTypeDesc.HasDefaultSupport) {
  331. if (comments != null && defaultValue is string) {
  332. DropDefaultAttribute(accessor, comments, memberTypeDesc.FullName);
  333. // do not generate intializers for the user prefered types if they do not have default capability
  334. AddWarningComment(comments, Res.GetString(Res.XmlDropAttributeValue, attributeName, mapping.TypeName, defaultValue.ToString()));
  335. }
  336. return;
  337. }
  338. if (memberTypeDesc.IsArrayLike && accessor is ElementAccessor) {
  339. if (comments != null && defaultValue is string) {
  340. DropDefaultAttribute(accessor, comments, memberTypeDesc.FullName);
  341. // do not generate intializers for array-like types
  342. AddWarningComment(comments, Res.GetString(Res.XmlDropArrayAttributeValue, attributeName, defaultValue.ToString(), ((ElementAccessor)accessor).Name));
  343. }
  344. return;
  345. }
  346. if (mapping.TypeDesc.IsMappedType && field != null && defaultValue is string) {
  347. SchemaImporterExtension extension = mapping.TypeDesc.ExtendedType.Extension;
  348. CodeExpression init = extension.ImportDefaultValue((string)defaultValue, mapping.TypeDesc.FullName);
  349. if (init != null) {
  350. if (ctor != null) {
  351. AddInitializationStatement(ctor, field, init);
  352. }
  353. else {
  354. field.InitExpression = extension.ImportDefaultValue((string)defaultValue, mapping.TypeDesc.FullName);
  355. }
  356. }
  357. if (comments != null) {
  358. DropDefaultAttribute(accessor, comments, mapping.TypeDesc.FullName);
  359. if (init == null) {
  360. AddWarningComment(comments, Res.GetString(Res.XmlNotKnownDefaultValue, extension.GetType().FullName, attributeName, (string)defaultValue, mapping.TypeName, mapping.Namespace));
  361. }
  362. }
  363. return;
  364. }
  365. object value = null;
  366. if (defaultValue is string || defaultValue == null) {
  367. value = ImportDefault(mapping, (string)defaultValue);
  368. }
  369. if (value == null) return;
  370. if (!(mapping is PrimitiveMapping)) {
  371. if (comments != null) {
  372. DropDefaultAttribute(accessor, comments, memberTypeDesc.FullName);
  373. AddWarningComment(comments, Res.GetString(Res.XmlDropNonPrimitiveAttributeValue, attributeName, defaultValue.ToString()));
  374. }
  375. return;
  376. }
  377. PrimitiveMapping pm = (PrimitiveMapping)mapping;
  378. if (comments != null && !pm.TypeDesc.HasDefaultSupport && pm.TypeDesc.IsMappedType) {
  379. // do not generate intializers for the user prefered types if they do not have default capability
  380. DropDefaultAttribute(accessor, comments, pm.TypeDesc.FullName);
  381. return;
  382. }
  383. if (value == DBNull.Value) {
  384. if (comments != null) {
  385. AddWarningComment(comments, Res.GetString(Res.XmlDropAttributeValue, attributeName, pm.TypeName, defaultValue.ToString()));
  386. }
  387. return;
  388. }
  389. CodeAttributeArgument[] arguments = null;
  390. CodeExpression initExpression = null;
  391. if (pm.IsList) {
  392. #if DEBUG
  393. // use exception in the place of Debug.Assert to avoid throwing asserts from a server process such as aspnet_ewp.exe
  394. if (value.GetType() != typeof(object[])) throw new InvalidOperationException(Res.GetString(Res.XmlInternalErrorDetails, "Default value for list should be object[], not " + value.GetType().Name));
  395. #endif
  396. object[] vals = (object[])value;
  397. CodeExpression[] initializers = new CodeExpression[vals.Length];
  398. for (int i = 0; i < vals.Length; i++) {
  399. GetDefaultValueArguments(pm, vals[i], out initializers[i]);
  400. }
  401. initExpression = new CodeArrayCreateExpression(field.Type, initializers);
  402. }
  403. else {
  404. arguments = GetDefaultValueArguments(pm, value, out initExpression);
  405. }
  406. if (field != null) {
  407. if (ctor != null) {
  408. AddInitializationStatement(ctor, field, initExpression);
  409. }
  410. else {
  411. field.InitExpression = initExpression;
  412. }
  413. }
  414. if (arguments != null && pm.TypeDesc.HasDefaultSupport && accessor.IsOptional && !accessor.IsFixed) {
  415. // Add [DefaultValueAttribute]
  416. CodeAttributeDeclaration attribute = new CodeAttributeDeclaration(typeof(DefaultValueAttribute).FullName, arguments);
  417. metadata.Add(attribute);
  418. }
  419. else if (comments != null) {
  420. DropDefaultAttribute(accessor, comments, memberTypeDesc.FullName);
  421. }
  422. }
  423. static void AddInitializationStatement(CodeConstructor ctor, CodeMemberField field, CodeExpression init) {
  424. CodeAssignStatement assign = new CodeAssignStatement();
  425. assign.Left = new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), field.Name);
  426. assign.Right = init;
  427. ctor.Statements.Add(assign);
  428. }
  429. static void DropDefaultAttribute(Accessor accessor, CodeCommentStatementCollection comments, string type) {
  430. if (!accessor.IsFixed && accessor.IsOptional) {
  431. AddWarningComment(comments, Res.GetString(Res.XmlDropDefaultAttribute, type));
  432. }
  433. }
  434. CodeTypeDeclaration ExportStruct(StructMapping mapping) {
  435. if (mapping.TypeDesc.IsRoot) {
  436. ExportRoot(mapping, typeof(XmlIncludeAttribute));
  437. return null;
  438. }
  439. string className = mapping.TypeDesc.Name;
  440. string baseName = mapping.TypeDesc.BaseTypeDesc == null || mapping.TypeDesc.BaseTypeDesc.IsRoot ? string.Empty : mapping.TypeDesc.BaseTypeDesc.FullName;
  441. CodeTypeDeclaration codeClass = new CodeTypeDeclaration(className);
  442. codeClass.IsPartial = CodeProvider.Supports(GeneratorSupport.PartialTypes);
  443. codeClass.Comments.Add(new CodeCommentStatement(Res.GetString(Res.XmlRemarks), true));
  444. CodeNamespace.Types.Add(codeClass);
  445. CodeConstructor ctor = new CodeConstructor();
  446. ctor.Attributes = (ctor.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Public;
  447. codeClass.Members.Add(ctor);
  448. if (mapping.TypeDesc.IsAbstract) {
  449. ctor.Attributes |= MemberAttributes.Abstract;
  450. }
  451. if (baseName != null && baseName.Length > 0) {
  452. codeClass.BaseTypes.Add(baseName);
  453. }
  454. else
  455. AddPropertyChangedNotifier(codeClass);
  456. codeClass.TypeAttributes |= TypeAttributes.Public;
  457. if (mapping.TypeDesc.IsAbstract) {
  458. codeClass.TypeAttributes |= TypeAttributes.Abstract;
  459. }
  460. AddIncludeMetadata(codeClass.CustomAttributes, mapping, typeof(XmlIncludeAttribute));
  461. if (mapping.IsSequence) {
  462. int generatedSequence = 0;
  463. for (int i = 0; i < mapping.Members.Length; i++) {
  464. MemberMapping member = mapping.Members[i];
  465. if (member.IsParticle && member.SequenceId < 0)
  466. member.SequenceId = generatedSequence++;
  467. }
  468. }
  469. if (GenerateProperties) {
  470. for (int i = 0; i < mapping.Members.Length; i++) {
  471. ExportProperty(codeClass, mapping.Members[i], mapping.Namespace, mapping.Scope, ctor);
  472. }
  473. }
  474. else {
  475. for (int i = 0; i < mapping.Members.Length; i++) {
  476. ExportMember(codeClass, mapping.Members[i], mapping.Namespace, ctor);
  477. }
  478. }
  479. for (int i = 0; i < mapping.Members.Length; i++) {
  480. if (mapping.Members[i].Xmlns != null)
  481. continue;
  482. EnsureTypesExported(mapping.Members[i].Elements, mapping.Namespace);
  483. EnsureTypesExported(mapping.Members[i].Attribute, mapping.Namespace);
  484. EnsureTypesExported(mapping.Members[i].Text, mapping.Namespace);
  485. }
  486. if (mapping.BaseMapping != null)
  487. ExportType(mapping.BaseMapping, null, mapping.Namespace, null, false);
  488. ExportDerivedStructs(mapping);
  489. CodeGenerator.ValidateIdentifiers(codeClass);
  490. if (ctor.Statements.Count == 0) codeClass.Members.Remove(ctor);
  491. return codeClass;
  492. }
  493. [PermissionSet(SecurityAction.InheritanceDemand, Name="FullTrust")]
  494. internal override void ExportDerivedStructs(StructMapping mapping) {
  495. for (StructMapping derived = mapping.DerivedMappings; derived != null; derived = derived.NextDerivedMapping)
  496. ExportType(derived, mapping.Namespace);
  497. }
  498. /// <include file='doc\XmlCodeExporter.uex' path='docs/doc[@for="XmlCodeExporter.AddMappingMetadata"]/*' />
  499. /// <devdoc>
  500. /// <para>[To be supplied.]</para>
  501. /// </devdoc>
  502. public void AddMappingMetadata(CodeAttributeDeclarationCollection metadata, XmlTypeMapping mapping, string ns) {
  503. mapping.CheckShallow();
  504. CheckScope(mapping.Scope);
  505. // For struct or enum mappings, we generate the XmlRoot on the struct/class/enum. For primitives
  506. // or arrays, there is nowhere to generate the XmlRoot, so we generate it elsewhere (on the
  507. // method for web services get/post).
  508. if (mapping.Mapping is StructMapping || mapping.Mapping is EnumMapping) return;
  509. AddRootMetadata(metadata, mapping.Mapping, Accessor.UnescapeName(mapping.Accessor.Name), mapping.Accessor.Namespace, mapping.Accessor);
  510. }
  511. /// <include file='doc\XmlCodeExporter.uex' path='docs/doc[@for="XmlCodeExporter.AddMappingMetadata1"]/*' />
  512. /// <devdoc>
  513. /// <para>[To be supplied.]</para>
  514. /// </devdoc>
  515. public void AddMappingMetadata(CodeAttributeDeclarationCollection metadata, XmlMemberMapping member, string ns, bool forceUseMemberName) {
  516. AddMemberMetadata(null, metadata, member.Mapping, ns, forceUseMemberName, null, null);
  517. }
  518. /// <include file='doc\XmlCodeExporter.uex' path='docs/doc[@for="XmlCodeExporter.AddMappingMetadata2"]/*' />
  519. /// <devdoc>
  520. /// <para>[To be supplied.]</para>
  521. /// </devdoc>
  522. public void AddMappingMetadata(CodeAttributeDeclarationCollection metadata, XmlMemberMapping member, string ns) {
  523. AddMemberMetadata(null, metadata, member.Mapping, ns, false, null, null);
  524. }
  525. void ExportArrayElements(CodeAttributeDeclarationCollection metadata, ArrayMapping array, string ns, TypeDesc elementTypeDesc, int nestingLevel) {
  526. for (int i = 0; i < array.Elements.Length; i++) {
  527. ElementAccessor arrayElement = array.Elements[i];
  528. TypeMapping elementMapping = arrayElement.Mapping;
  529. string elementName = Accessor.UnescapeName(arrayElement.Name);
  530. bool sameName = arrayElement.Mapping.TypeDesc.IsArray ? false : elementName == arrayElement.Mapping.TypeName;
  531. bool sameElementType = elementMapping.TypeDesc == elementTypeDesc;
  532. bool sameElementNs = arrayElement.Form == XmlSchemaForm.Unqualified || arrayElement.Namespace == ns;
  533. bool sameNullable = arrayElement.IsNullable == elementMapping.TypeDesc.IsNullable;
  534. bool defaultForm = arrayElement.Form != XmlSchemaForm.Unqualified;
  535. if (!sameName || !sameElementType || !sameElementNs || !sameNullable || !defaultForm || nestingLevel > 0)
  536. ExportArrayItem(metadata, sameName ? null : elementName, sameElementNs ? null : arrayElement.Namespace, sameElementType ? null : elementMapping.TypeDesc, elementMapping.TypeDesc, arrayElement.IsNullable, defaultForm ? XmlSchemaForm.None : arrayElement.Form, nestingLevel);
  537. if (elementMapping is ArrayMapping)
  538. ExportArrayElements(metadata, (ArrayMapping) elementMapping, ns, elementTypeDesc.ArrayElementTypeDesc, nestingLevel+1);
  539. }
  540. }
  541. void AddMemberMetadata(CodeMemberField field, CodeAttributeDeclarationCollection metadata, MemberMapping member, string ns, bool forceUseMemberName, CodeCommentStatementCollection comments, CodeConstructor ctor) {
  542. if (member.Xmlns != null) {
  543. CodeAttributeDeclaration attribute = new CodeAttributeDeclaration(typeof(XmlNamespaceDeclarationsAttribute).FullName);
  544. metadata.Add(attribute);
  545. }
  546. else if (member.Attribute != null) {
  547. AttributeAccessor attribute = member.Attribute;
  548. if (attribute.Any)
  549. ExportAnyAttribute(metadata);
  550. else {
  551. TypeMapping mapping = (TypeMapping)attribute.Mapping;
  552. string attrName = Accessor.UnescapeName(attribute.Name);
  553. bool sameType = mapping.TypeDesc == member.TypeDesc ||
  554. (member.TypeDesc.IsArrayLike && mapping.TypeDesc == member.TypeDesc.ArrayElementTypeDesc);
  555. bool sameName = attrName == member.Name && !forceUseMemberName;
  556. bool sameNs = attribute.Namespace == ns;
  557. bool defaultForm = attribute.Form != XmlSchemaForm.Qualified;
  558. ExportAttribute(metadata,
  559. sameName ? null : attrName,
  560. sameNs || defaultForm ? null : attribute.Namespace,
  561. sameType ? null : mapping.TypeDesc,
  562. mapping.TypeDesc,
  563. defaultForm ? XmlSchemaForm.None : attribute.Form);
  564. AddDefaultValueAttribute(field, metadata, attribute.Default, mapping, comments, member.TypeDesc, attribute, ctor);
  565. }
  566. }
  567. else {
  568. if (member.Text != null) {
  569. TypeMapping mapping = (TypeMapping)member.Text.Mapping;
  570. bool sameType = mapping.TypeDesc == member.TypeDesc ||
  571. (member.TypeDesc.IsArrayLike && mapping.TypeDesc == member.TypeDesc.ArrayElementTypeDesc);
  572. ExportText(metadata, sameType ? null : mapping.TypeDesc, mapping.TypeDesc.IsAmbiguousDataType ? mapping.TypeDesc.DataType.Name : null);
  573. }
  574. if (member.Elements.Length == 1) {
  575. ElementAccessor element = member.Elements[0];
  576. TypeMapping mapping = (TypeMapping)element.Mapping;
  577. string elemName = Accessor.UnescapeName(element.Name);
  578. bool sameName = ((elemName == member.Name) && !forceUseMemberName);
  579. bool isArray = mapping is ArrayMapping;
  580. bool sameNs = element.Namespace == ns;
  581. bool defaultForm = element.Form != XmlSchemaForm.Unqualified;
  582. if (element.Any)
  583. ExportAnyElement(metadata, elemName, element.Namespace, member.SequenceId);
  584. else if (isArray) {
  585. bool sameType = mapping.TypeDesc == member.TypeDesc;
  586. ArrayMapping array = (ArrayMapping)mapping;
  587. if (!sameName || !sameNs || element.IsNullable || !defaultForm || member.SequenceId != -1)
  588. ExportArray(metadata, sameName ? null : elemName, sameNs ? null : element.Namespace, element.IsNullable, defaultForm ? XmlSchemaForm.None : element.Form, member.SequenceId);
  589. else if (mapping.TypeDesc.ArrayElementTypeDesc == new TypeScope().GetTypeDesc(typeof(byte))) {
  590. // special case for byte[]. It can be a primitive (base64Binary or hexBinary), or it can
  591. // be an array of bytes. Our default is primitive; specify [XmlArray] to get array behavior.
  592. ExportArray(metadata, null, null, false, XmlSchemaForm.None, member.SequenceId);
  593. }
  594. ExportArrayElements(metadata, array, element.Namespace, member.TypeDesc.ArrayElementTypeDesc, 0);
  595. }
  596. else {
  597. bool sameType = mapping.TypeDesc == member.TypeDesc ||
  598. (member.TypeDesc.IsArrayLike && mapping.TypeDesc == member.TypeDesc.ArrayElementTypeDesc);
  599. if (member.TypeDesc.IsArrayLike)
  600. sameName = false;
  601. ExportElement(metadata, sameName ? null : elemName, sameNs ? null : element.Namespace, sameType ? null : mapping.TypeDesc, mapping.TypeDesc, element.IsNullable, defaultForm ? XmlSchemaForm.None : element.Form, member.SequenceId);
  602. }
  603. AddDefaultValueAttribute(field, metadata, element.Default, mapping, comments, member.TypeDesc, element, ctor);
  604. }
  605. else {
  606. for (int i = 0; i < member.Elements.Length; i++) {
  607. ElementAccessor element = member.Elements[i];
  608. string elemName = Accessor.UnescapeName(element.Name);
  609. bool sameNs = element.Namespace == ns;
  610. if (element.Any)
  611. ExportAnyElement(metadata, elemName, element.Namespace, member.SequenceId);
  612. else {
  613. bool defaultForm = element.Form != XmlSchemaForm.Unqualified;
  614. ExportElement(metadata, elemName, sameNs ? null : element.Namespace, ((TypeMapping)element.Mapping).TypeDesc, ((TypeMapping)element.Mapping).TypeDesc, element.IsNullable, defaultForm ? XmlSchemaForm.None : element.Form, member.SequenceId);
  615. }
  616. }
  617. }
  618. if (member.ChoiceIdentifier != null) {
  619. CodeAttributeDeclaration attribute = new CodeAttributeDeclaration(typeof(XmlChoiceIdentifierAttribute).FullName);
  620. attribute.Arguments.Add(new CodeAttributeArgument(new CodePrimitiveExpression(member.ChoiceIdentifier.MemberName)));
  621. metadata.Add(attribute);
  622. }
  623. if (member.Ignore) {
  624. CodeAttributeDeclaration attribute = new CodeAttributeDeclaration(typeof(XmlIgnoreAttribute).FullName);
  625. metadata.Add(attribute);
  626. }
  627. }
  628. }
  629. void ExportMember(CodeTypeDeclaration codeClass, MemberMapping member, string ns, CodeConstructor ctor) {
  630. string fieldType = member.GetTypeName(CodeProvider);
  631. CodeMemberField field = new CodeMemberField(fieldType, member.Name);
  632. field.Attributes = (field.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Public;
  633. field.Comments.Add(new CodeCommentStatement(Res.GetString(Res.XmlRemarks), true));
  634. codeClass.Members.Add(field);
  635. AddMemberMetadata(field, field.CustomAttributes, member, ns, false, field.Comments, ctor);
  636. if (member.CheckSpecified != SpecifiedAccessor.None) {
  637. field = new CodeMemberField(typeof(bool).FullName, member.Name + "Specified");
  638. field.Attributes = (field.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Public;
  639. field.Comments.Add(new CodeCommentStatement(Res.GetString(Res.XmlRemarks), true));
  640. CodeAttributeDeclaration attribute = new CodeAttributeDeclaration(typeof(XmlIgnoreAttribute).FullName);
  641. field.CustomAttributes.Add(attribute);
  642. codeClass.Members.Add(field);
  643. }
  644. }
  645. void ExportProperty(CodeTypeDeclaration codeClass, MemberMapping member, string ns, CodeIdentifiers memberScope, CodeConstructor ctor) {
  646. string fieldName = memberScope.AddUnique(MakeFieldName(member.Name), member);
  647. string fieldType = member.GetTypeName(CodeProvider);
  648. // need to create a private field
  649. CodeMemberField field = new CodeMemberField(fieldType, fieldName);
  650. field.Attributes = MemberAttributes.Private;
  651. codeClass.Members.Add(field);
  652. CodeMemberProperty prop = CreatePropertyDeclaration(field, member.Name, fieldType);
  653. prop.Comments.Add(new CodeCommentStatement(Res.GetString(Res.XmlRemarks), true));
  654. AddMemberMetadata(field, prop.CustomAttributes, member, ns, false, prop.Comments, ctor);
  655. codeClass.Members.Add(prop);
  656. if (member.CheckSpecified != SpecifiedAccessor.None) {
  657. field = new CodeMemberField(typeof(bool).FullName, fieldName + "Specified");
  658. field.Attributes = MemberAttributes.Private;
  659. codeClass.Members.Add(field);
  660. prop = CreatePropertyDeclaration(field, member.Name + "Specified", typeof(bool).FullName);
  661. prop.Comments.Add(new CodeCommentStatement(Res.GetString(Res.XmlRemarks), true));
  662. CodeAttributeDeclaration attribute = new CodeAttributeDeclaration(typeof(XmlIgnoreAttribute).FullName);
  663. prop.CustomAttributes.Add(attribute);
  664. codeClass.Members.Add(prop);
  665. }
  666. }
  667. void ExportText(CodeAttributeDeclarationCollection metadata, TypeDesc typeDesc, string dataType) {
  668. CodeAttributeDeclaration attribute = new CodeAttributeDeclaration(typeof(XmlTextAttribute).FullName);
  669. if (typeDesc != null) {
  670. attribute.Arguments.Add(new CodeAttributeArgument(new CodeTypeOfExpression(typeDesc.FullName)));
  671. }
  672. if (dataType != null) {
  673. attribute.Arguments.Add(new CodeAttributeArgument("DataType", new CodePrimitiveExpression(dataType)));
  674. }
  675. metadata.Add(attribute);
  676. }
  677. void ExportAttribute(CodeAttributeDeclarationCollection metadata, string name, string ns, TypeDesc typeDesc, TypeDesc dataTypeDesc, XmlSchemaForm form) {
  678. ExportMetadata(metadata, typeof(XmlAttributeAttribute), name, ns, typeDesc, dataTypeDesc, null, form, 0, -1);
  679. }
  680. void ExportArrayItem(CodeAttributeDeclarationCollection metadata, string name, string ns, TypeDesc typeDesc, TypeDesc dataTypeDesc, bool isNullable, XmlSchemaForm form, int nestingLevel) {
  681. ExportMetadata(metadata, typeof(XmlArrayItemAttribute), name, ns, typeDesc, dataTypeDesc, isNullable ? null : (object)false, form, nestingLevel, -1);
  682. }
  683. void ExportElement(CodeAttributeDeclarationCollection metadata, string name, string ns, TypeDesc typeDesc, TypeDesc dataTypeDesc, bool isNullable, XmlSchemaForm form, int sequenceId) {
  684. ExportMetadata(metadata, typeof(XmlElementAttribute), name, ns, typeDesc, dataTypeDesc, isNullable ? (object)true : null, form, 0, sequenceId);
  685. }
  686. void ExportArray(CodeAttributeDeclarationCollection metadata, string name, string ns, bool isNullable, XmlSchemaForm form, int sequenceId) {
  687. ExportMetadata(metadata, typeof(XmlArrayAttribute), name, ns, null, null, isNullable ? (object)true : null, form, 0, sequenceId);
  688. }
  689. void ExportMetadata(CodeAttributeDeclarationCollection metadata, Type attributeType, string name, string ns, TypeDesc typeDesc, TypeDesc dataTypeDesc, object isNullable, XmlSchemaForm form, int nestingLevel, int sequenceId) {
  690. CodeAttributeDeclaration attribute = new CodeAttributeDeclaration(attributeType.FullName);
  691. if (name != null) {
  692. attribute.Arguments.Add(new CodeAttributeArgument(new CodePrimitiveExpression(name)));
  693. }
  694. if (typeDesc != null) {
  695. if (isNullable != null && (bool)isNullable && typeDesc.IsValueType && !typeDesc.IsMappedType && CodeProvider.Supports(GeneratorSupport.GenericTypeReference)) {
  696. attribute.Arguments.Add(new CodeAttributeArgument(new CodeTypeOfExpression("System.Nullable`1[" + typeDesc.FullName + "]")));
  697. isNullable = null;
  698. }
  699. else {
  700. attribute.Arguments.Add(new CodeAttributeArgument(new CodeTypeOfExpression(typeDesc.FullName)));
  701. }
  702. }
  703. if (form != XmlSchemaForm.None) {
  704. attribute.Arguments.Add(new CodeAttributeArgument("Form", new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(typeof(XmlSchemaForm).FullName), Enum.Format(typeof(XmlSchemaForm), form, "G"))));
  705. if (form == XmlSchemaForm.Unqualified && ns != null && ns.Length == 0) {
  706. ns = null;
  707. }
  708. }
  709. if (ns != null ) {
  710. attribute.Arguments.Add(new CodeAttributeArgument("Namespace", new CodePrimitiveExpression(ns)));
  711. }
  712. if (dataTypeDesc != null && dataTypeDesc.IsAmbiguousDataType && !dataTypeDesc.IsMappedType) {
  713. attribute.Arguments.Add(new CodeAttributeArgument("DataType", new CodePrimitiveExpression(dataTypeDesc.DataType.Name)));
  714. }
  715. if (isNullable != null) {
  716. attribute.Arguments.Add(new CodeAttributeArgument("IsNullable", new CodePrimitiveExpression((bool)isNullable)));
  717. }
  718. if (nestingLevel > 0) {
  719. attribute.Arguments.Add(new CodeAttributeArgument("NestingLevel", new CodePrimitiveExpression(nestingLevel)));
  720. }
  721. if (sequenceId >= 0) {
  722. attribute.Arguments.Add(new CodeAttributeArgument("Order", new CodePrimitiveExpression(sequenceId)));
  723. }
  724. if (attribute.Arguments.Count == 0 && attributeType == typeof(XmlElementAttribute)) return;
  725. metadata.Add(attribute);
  726. }
  727. void ExportAnyElement(CodeAttributeDeclarationCollection metadata, string name, string ns, int sequenceId) {
  728. CodeAttributeDeclaration attribute = new CodeAttributeDeclaration(typeof(XmlAnyElementAttribute).FullName);
  729. if (name != null && name.Length > 0) {
  730. attribute.Arguments.Add(new CodeAttributeArgument("Name", new CodePrimitiveExpression(name)));
  731. }
  732. if (ns != null) {
  733. attribute.Arguments.Add(new CodeAttributeArgument("Namespace", new CodePrimitiveExpression(ns)));
  734. }
  735. if (sequenceId >= 0) {
  736. attribute.Arguments.Add(new CodeAttributeArgument("Order", new CodePrimitiveExpression(sequenceId)));
  737. }
  738. metadata.Add(attribute);
  739. }
  740. void ExportAnyAttribute(CodeAttributeDeclarationCollection metadata) {
  741. metadata.Add(new CodeAttributeDeclaration(typeof(XmlAnyAttributeAttribute).FullName));
  742. }
  743. internal override void EnsureTypesExported(Accessor[] accessors, string ns) {
  744. if (accessors == null) return;
  745. for (int i = 0; i < accessors.Length; i++)
  746. EnsureTypesExported(accessors[i], ns);
  747. }
  748. void EnsureTypesExported(Accessor accessor, string ns) {
  749. if (accessor == null) return;
  750. ExportType(accessor.Mapping, null, ns, null, false);
  751. }
  752. }
  753. }