SerializationMap.cs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783
  1. //
  2. // SerializationMap.cs
  3. //
  4. // Author:
  5. // Atsushi Enomoto <[email protected]>
  6. // Ankit Jain <[email protected]>
  7. // Duncan Mak ([email protected])
  8. // Eyal Alaluf ([email protected])
  9. //
  10. // Copyright (C) 2005 Novell, Inc. http://www.novell.com
  11. // Copyright (C) 2006 Novell, Inc. http://www.novell.com
  12. //
  13. // Permission is hereby granted, free of charge, to any person obtaining
  14. // a copy of this software and associated documentation files (the
  15. // "Software"), to deal in the Software without restriction, including
  16. // without limitation the rights to use, copy, modify, merge, publish,
  17. // distribute, sublicense, and/or sell copies of the Software, and to
  18. // permit persons to whom the Software is furnished to do so, subject to
  19. // the following conditions:
  20. //
  21. // The above copyright notice and this permission notice shall be
  22. // included in all copies or substantial portions of the Software.
  23. //
  24. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  25. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  26. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  27. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  28. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  29. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  30. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  31. //
  32. #if NET_2_0
  33. using System;
  34. using System.Collections;
  35. using System.Collections.Generic;
  36. using System.Collections.ObjectModel;
  37. using System.Reflection;
  38. using System.Xml;
  39. using System.Xml.Schema;
  40. using System.Xml.Serialization;
  41. using QName = System.Xml.XmlQualifiedName;
  42. namespace System.Runtime.Serialization
  43. {
  44. /*
  45. XmlFormatter implementation design inference:
  46. type definitions:
  47. - No XML Schema types are directly used. There are some maps from
  48. xs:blahType to ms:blahType where the namespaceURI for prefix "ms" is
  49. "http://schemas.microsoft.com/2003/10/Serialization/" .
  50. serializable types:
  51. - An object being serialized 1) must be of type System.Object, or
  52. 2) must be null, or 3) must have either a [DataContract] attribute
  53. or a [Serializable] attribute to be serializable.
  54. - When the object is either of type System.Object or null, then the
  55. XML type is "anyType".
  56. - When the object is [Serializable], then the runtime-serialization
  57. compatible object graph is written.
  58. - Otherwise the serialization is based on contract attributes.
  59. ([Serializable] takes precedence).
  60. type derivation:
  61. - For type A to be serializable, the base type B of A must be
  62. serializable.
  63. - If a type which is [Serializable] and whose base type has a
  64. [DataContract], then for base type members [DataContract] is taken.
  65. - It is vice versa i.e. if the base type is [Serializable] and the
  66. derived type has a [DataContract], then [Serializable] takes place
  67. for base members.
  68. known type collection:
  69. - It internally manages mapping store keyed by contract QNames.
  70. KnownTypeCollection.Add() checks if the same QName contract already
  71. exists (and raises InvalidOperationException if required).
  72. */
  73. internal abstract class SerializationMap
  74. {
  75. public const BindingFlags AllInstanceFlags =
  76. BindingFlags.Public | BindingFlags.NonPublic |
  77. BindingFlags.Instance;
  78. public readonly KnownTypeCollection KnownTypes;
  79. public readonly Type RuntimeType;
  80. public readonly QName XmlName;
  81. public bool IsReference; // new in 3.5 SP1
  82. public List<DataMemberInfo> Members;
  83. #if !NET_2_1
  84. XmlSchemaSet schema_set;
  85. #endif
  86. //FIXME FIXME
  87. Dictionary<Type, QName> qname_table = new Dictionary<Type, QName> ();
  88. protected SerializationMap (
  89. Type type, QName qname, KnownTypeCollection knownTypes)
  90. {
  91. KnownTypes = knownTypes;
  92. RuntimeType = type;
  93. if (qname.Namespace == String.Empty)
  94. qname = new QName (qname.Name,
  95. "http://schemas.datacontract.org/2004/07/" + type.Namespace);
  96. XmlName = qname;
  97. Members = new List<DataMemberInfo> ();
  98. }
  99. public DataMemberAttribute GetDataMemberAttribute (
  100. MemberInfo mi)
  101. {
  102. object [] atts = mi.GetCustomAttributes (
  103. typeof (DataMemberAttribute), false);
  104. if (atts.Length == 0)
  105. return null;
  106. return (DataMemberAttribute) atts [0];
  107. }
  108. bool IsPrimitive (Type type)
  109. {
  110. return (Type.GetTypeCode (type) != TypeCode.Object || type == typeof (object));
  111. }
  112. #if !NET_2_1
  113. /* Returns the XmlSchemaType AND adds it to @schemas */
  114. public virtual XmlSchemaType GetSchemaType (XmlSchemaSet schemas, Dictionary<QName, XmlSchemaType> generated_schema_types)
  115. {
  116. if (IsPrimitive (RuntimeType))
  117. return null;
  118. if (generated_schema_types.ContainsKey (XmlName)) // Caching
  119. return generated_schema_types [XmlName] as XmlSchemaType;
  120. XmlSchemaComplexType complex_type = null;
  121. complex_type = new XmlSchemaComplexType ();
  122. complex_type.Name = XmlName.Name;
  123. generated_schema_types [XmlName] = complex_type;
  124. if (RuntimeType.BaseType == typeof (object)) {
  125. complex_type.Particle = GetSequence (schemas, generated_schema_types);
  126. } else {
  127. //Has a non-System.Object base class
  128. XmlSchemaComplexContentExtension extension = new XmlSchemaComplexContentExtension ();
  129. XmlSchemaComplexContent content = new XmlSchemaComplexContent ();
  130. complex_type.ContentModel = content;
  131. content.Content = extension;
  132. KnownTypes.Add (RuntimeType.BaseType);
  133. SerializationMap map = KnownTypes.FindUserMap (RuntimeType.BaseType);
  134. //FIXME: map == null ?
  135. map.GetSchemaType (schemas, generated_schema_types);
  136. extension.Particle = GetSequence (schemas, generated_schema_types);
  137. extension.BaseTypeName = GetQualifiedName (RuntimeType.BaseType);
  138. }
  139. XmlSchemaElement schemaElement = GetSchemaElement (XmlName, complex_type);
  140. XmlSchema schema = GetSchema (schemas, XmlName.Namespace);
  141. schema.Items.Add (complex_type);
  142. schema.Items.Add (schemaElement);
  143. schemas.Reprocess (schema);
  144. return complex_type;
  145. }
  146. /* Returns the <xs:sequence> for the data members */
  147. XmlSchemaSequence GetSequence (XmlSchemaSet schemas,
  148. Dictionary<QName, XmlSchemaType> generated_schema_types)
  149. {
  150. List<DataMemberInfo> members = GetMembers ();
  151. XmlSchema schema = GetSchema (schemas, XmlName.Namespace);
  152. XmlSchemaSequence sequence = new XmlSchemaSequence ();
  153. foreach (DataMemberInfo dmi in members) {
  154. // delegates are not supported.
  155. if (!dmi.MemberType.IsAbstract && typeof (System.Delegate).IsAssignableFrom (dmi.MemberType))
  156. continue;
  157. XmlSchemaElement element = new XmlSchemaElement ();
  158. element.Name = dmi.XmlName;
  159. KnownTypes.Add (dmi.MemberType);
  160. SerializationMap map = KnownTypes.FindUserMap (dmi.MemberType);
  161. if (map != null) {
  162. XmlSchemaType schema_type = map.GetSchemaType (schemas, generated_schema_types);
  163. if (schema_type is XmlSchemaComplexType)
  164. element.IsNillable = true;
  165. } else {
  166. //Primitive type
  167. if (dmi.MemberType == typeof (string))
  168. element.IsNillable = true;
  169. }
  170. element.MinOccurs = 0;
  171. element.SchemaTypeName = GetQualifiedName (dmi.MemberType);
  172. AddImport (schema, element.SchemaTypeName.Namespace);
  173. sequence.Items.Add (element);
  174. }
  175. schemas.Reprocess (schema);
  176. return sequence;
  177. }
  178. //FIXME: Replace with a dictionary ?
  179. void AddImport (XmlSchema schema, string ns)
  180. {
  181. if (ns == XmlSchema.Namespace || schema.TargetNamespace == ns)
  182. return;
  183. foreach (XmlSchemaObject o in schema.Includes) {
  184. XmlSchemaImport import = o as XmlSchemaImport;
  185. if (import == null)
  186. continue;
  187. if (import.Namespace == ns)
  188. return;
  189. }
  190. XmlSchemaImport imp = new XmlSchemaImport ();
  191. imp.Namespace = ns;
  192. schema.Includes.Add (imp);
  193. }
  194. #endif
  195. //Returns list of data members for this type ONLY
  196. public virtual List<DataMemberInfo> GetMembers ()
  197. {
  198. throw new NotImplementedException (String.Format ("Implement me for {0}", this));
  199. }
  200. #if !NET_2_1
  201. protected XmlSchemaElement GetSchemaElement (QName qname, XmlSchemaType schemaType)
  202. {
  203. XmlSchemaElement schemaElement = new XmlSchemaElement ();
  204. schemaElement.Name = qname.Name;
  205. schemaElement.SchemaTypeName = qname;
  206. if (schemaType is XmlSchemaComplexType)
  207. schemaElement.IsNillable = true;
  208. return schemaElement;
  209. }
  210. protected XmlSchema GetSchema (XmlSchemaSet schemas, string ns)
  211. {
  212. ICollection colln = schemas.Schemas (ns);
  213. if (colln.Count > 0) {
  214. if (colln.Count > 1)
  215. throw new Exception (String.Format (
  216. "More than 1 schema for namespace '{0}' found.", ns));
  217. foreach (object o in colln)
  218. //return colln [0]
  219. return (o as XmlSchema);
  220. }
  221. XmlSchema schema = new XmlSchema ();
  222. schema.TargetNamespace = ns;
  223. schema.ElementFormDefault = XmlSchemaForm.Qualified;
  224. schemas.Add (schema);
  225. return schema;
  226. }
  227. #endif
  228. //FIXME: redundant?
  229. protected XmlQualifiedName GetQualifiedName (Type type)
  230. {
  231. if (qname_table.ContainsKey (type))
  232. return qname_table [type];
  233. QName qname = KnownTypes.GetQName (type);
  234. if (qname.Namespace == KnownTypeCollection.MSSimpleNamespace)
  235. qname = new QName (qname.Name, XmlSchema.Namespace);
  236. qname_table [type] = qname;
  237. return qname;
  238. }
  239. public virtual void Serialize (object graph,
  240. XmlFormatterSerializer serializer)
  241. {
  242. string label = null;
  243. if (IsReference) {
  244. label = (string) serializer.References [graph];
  245. if (label != null) {
  246. serializer.Writer.WriteAttributeString ("z", "Ref", KnownTypeCollection.MSSimpleNamespace, label);
  247. return;
  248. }
  249. label = "i" + (serializer.References.Count + 1);
  250. serializer.References.Add (graph, label);
  251. }
  252. else if (serializer.SerializingObjects.Contains (graph))
  253. throw new SerializationException (String.Format ("Circular reference of an object in the object graph was found: '{0}' of type {1}", graph, graph.GetType ()));
  254. serializer.SerializingObjects.Add (graph);
  255. if (label != null)
  256. serializer.Writer.WriteAttributeString ("z", "Id", KnownTypeCollection.MSSimpleNamespace, label);
  257. SerializeNonReference (graph, serializer);
  258. serializer.SerializingObjects.Remove (graph);
  259. }
  260. public virtual void SerializeNonReference (object graph,
  261. XmlFormatterSerializer serializer)
  262. {
  263. foreach (DataMemberInfo dmi in Members) {
  264. FieldInfo fi = dmi.Member as FieldInfo;
  265. PropertyInfo pi = fi == null ?
  266. (PropertyInfo) dmi.Member : null;
  267. Type type = fi != null ?
  268. fi.FieldType : pi.PropertyType;
  269. object value = fi != null ?
  270. fi.GetValue (graph) :
  271. pi.GetValue (graph, null);
  272. serializer.WriteStartElement (dmi.XmlName, dmi.XmlRootNamespace, dmi.XmlNamespace);
  273. serializer.Serialize (type, value);
  274. serializer.WriteEndElement ();
  275. }
  276. }
  277. /* Deserialize non-primitive types */
  278. public virtual object DeserializeContent (XmlReader reader,
  279. XmlFormatterDeserializer deserializer)
  280. {
  281. object instance = FormatterServices.GetUninitializedObject (RuntimeType);
  282. int depth = reader.NodeType == XmlNodeType.None ? reader.Depth : reader.Depth - 1;
  283. bool [] filled = new bool [Members.Count];
  284. int memberInd = -1;
  285. while (reader.NodeType == XmlNodeType.Element && reader.Depth > depth) {
  286. DataMemberInfo dmi = null;
  287. for (int i = memberInd + 1; i < Members.Count; i++) {
  288. if (reader.LocalName == Members [i].XmlName &&
  289. reader.NamespaceURI == Members [i].XmlRootNamespace) {
  290. memberInd = i;
  291. dmi = Members [i];
  292. break;
  293. }
  294. }
  295. if (dmi == null) {
  296. reader.Skip ();
  297. continue;
  298. }
  299. SetValue (dmi, instance, deserializer.Deserialize (dmi.MemberType, reader));
  300. filled [memberInd] = true;
  301. }
  302. for (int i = 0; i < Members.Count; i++)
  303. if (!filled [i] && Members [i].IsRequired)
  304. throw MissingRequiredMember (Members [i], reader);
  305. return instance;
  306. }
  307. // For now it could be private.
  308. protected Exception MissingRequiredMember (DataMemberInfo dmi, XmlReader reader)
  309. {
  310. return new ArgumentException (String.Format ("Data contract member {0} is required, but missing in the input XML.", new QName (dmi.XmlName, dmi.XmlNamespace)));
  311. }
  312. // For now it could be private.
  313. protected void SetValue (DataMemberInfo dmi, object obj, object value)
  314. {
  315. if (dmi.Member is PropertyInfo)
  316. ((PropertyInfo) dmi.Member).SetValue (obj, value, null);
  317. else
  318. ((FieldInfo) dmi.Member).SetValue (obj, value);
  319. }
  320. protected DataMemberInfo CreateDataMemberInfo (DataMemberAttribute dma, MemberInfo mi, Type type)
  321. {
  322. KnownTypes.Add (type);
  323. QName qname = KnownTypes.GetQName (type);
  324. string rootNamespace = KnownTypes.GetQName (mi.DeclaringType).Namespace;
  325. if (KnownTypeCollection.IsPrimitiveType (qname))
  326. return new DataMemberInfo (mi, dma, rootNamespace, null);
  327. else
  328. return new DataMemberInfo (mi, dma, rootNamespace, qname.Namespace);
  329. }
  330. }
  331. internal class XmlSerializableMap : SerializationMap
  332. {
  333. public XmlSerializableMap (Type type, QName qname, KnownTypeCollection knownTypes)
  334. : base (type, qname, knownTypes)
  335. {
  336. }
  337. public override void Serialize (object graph, XmlFormatterSerializer serializer)
  338. {
  339. IXmlSerializable ixs = graph as IXmlSerializable;
  340. if (ixs == null)
  341. //FIXME: Throw what exception here?
  342. throw new SerializationException ();
  343. ixs.WriteXml (serializer.Writer);
  344. }
  345. }
  346. internal class SharedContractMap : SerializationMap
  347. {
  348. public SharedContractMap (
  349. Type type, QName qname, KnownTypeCollection knownTypes)
  350. : base (type, qname, knownTypes)
  351. {
  352. Type baseType = type;
  353. List <DataMemberInfo> members = new List <DataMemberInfo> ();
  354. object [] atts = type.GetCustomAttributes (
  355. typeof (DataContractAttribute), false);
  356. IsReference = atts.Length > 0 ? (((DataContractAttribute) atts [0]).IsReference) : false;
  357. while (baseType != null) {
  358. QName bqname = knownTypes.GetQName (baseType);
  359. members = GetMembers (baseType, bqname, true);
  360. Members.InsertRange (0, members);
  361. members.Clear ();
  362. baseType = baseType.BaseType;
  363. }
  364. // Members.Sort (delegate (
  365. // DataMemberInfo d1, DataMemberInfo d2) {
  366. // return d1.Order - d2.Order;
  367. // });
  368. }
  369. List<DataMemberInfo> GetMembers (Type type, QName qname, bool declared_only)
  370. {
  371. List<DataMemberInfo> data_members = new List<DataMemberInfo> ();
  372. BindingFlags flags = AllInstanceFlags;
  373. if (declared_only)
  374. flags |= BindingFlags.DeclaredOnly;
  375. foreach (PropertyInfo pi in type.GetProperties (flags)) {
  376. DataMemberAttribute dma =
  377. GetDataMemberAttribute (pi);
  378. if (dma == null)
  379. continue;
  380. if (!pi.CanRead || !pi.CanWrite)
  381. throw new InvalidDataContractException (String.Format (
  382. "DataMember property {0} must have both getter and setter.", pi));
  383. data_members.Add (CreateDataMemberInfo (dma, pi, pi.PropertyType));
  384. }
  385. foreach (FieldInfo fi in type.GetFields (flags)) {
  386. DataMemberAttribute dma =
  387. GetDataMemberAttribute (fi);
  388. if (dma == null)
  389. continue;
  390. if (fi.IsInitOnly)
  391. throw new InvalidDataContractException (String.Format (
  392. "DataMember field {0} must not be read-only.", fi));
  393. data_members.Add (CreateDataMemberInfo (dma, fi, fi.FieldType));
  394. }
  395. data_members.Sort (DataMemberInfo.DataMemberInfoComparer.Instance);
  396. return data_members;
  397. }
  398. public override List<DataMemberInfo> GetMembers ()
  399. {
  400. return GetMembers (RuntimeType, XmlName, true);
  401. }
  402. }
  403. internal class CollectionTypeMap : SerializationMap
  404. {
  405. Type element_type;
  406. QName element_qname;
  407. public CollectionTypeMap (
  408. Type type, Type elementType,
  409. QName qname, KnownTypeCollection knownTypes)
  410. : base (type, qname, knownTypes)
  411. {
  412. element_type = elementType;
  413. element_qname = KnownTypes.GetQName (element_type);
  414. object [] atts = type.GetCustomAttributes (
  415. typeof (CollectionDataContractAttribute), false);
  416. IsReference = atts.Length > 0 ? (((CollectionDataContractAttribute) atts [0]).IsReference) : false;
  417. }
  418. public override void SerializeNonReference (object graph,
  419. XmlFormatterSerializer serializer)
  420. {
  421. string ns = element_qname.Namespace;
  422. if (ns == KnownTypeCollection.MSSimpleNamespace)
  423. ns = KnownTypeCollection.MSArraysNamespace;
  424. foreach (object o in (IEnumerable) graph) {
  425. serializer.WriteStartElement (element_qname.Name, XmlName.Namespace, ns);
  426. serializer.Serialize (element_type, o);
  427. serializer.WriteEndElement ();
  428. }
  429. }
  430. public override object DeserializeContent(XmlReader reader, XmlFormatterDeserializer deserializer)
  431. {
  432. object instance;
  433. if (RuntimeType.IsArray)
  434. instance = new ArrayList ();
  435. else
  436. instance = Activator.CreateInstance (RuntimeType, true);
  437. int depth = reader.NodeType == XmlNodeType.None ? reader.Depth : reader.Depth - 1;
  438. while (reader.NodeType == XmlNodeType.Element && reader.Depth > depth) {
  439. object elem = deserializer.Deserialize (element_type, reader);
  440. if (instance is IList)
  441. ((IList)instance).Add (elem);
  442. else
  443. throw new NotImplementedException (String.Format ("Type {0} is not supported", RuntimeType));
  444. }
  445. if (RuntimeType.IsArray)
  446. return ((ArrayList)instance).ToArray (element_type);
  447. return instance;
  448. }
  449. public override List<DataMemberInfo> GetMembers ()
  450. {
  451. //Shouldn't come here at all!
  452. throw new NotImplementedException ();
  453. }
  454. #if !NET_2_1
  455. public override XmlSchemaType GetSchemaType (XmlSchemaSet schemas, Dictionary<QName, XmlSchemaType> generated_schema_types)
  456. {
  457. if (generated_schema_types.ContainsKey (XmlName))
  458. return null;
  459. if (generated_schema_types.ContainsKey (XmlName))
  460. return generated_schema_types [XmlName];
  461. QName element_qname = GetQualifiedName (element_type);
  462. XmlSchemaComplexType complex_type = new XmlSchemaComplexType ();
  463. complex_type.Name = XmlName.Name;
  464. XmlSchemaSequence sequence = new XmlSchemaSequence ();
  465. XmlSchemaElement element = new XmlSchemaElement ();
  466. element.MinOccurs = 0;
  467. element.MaxOccursString = "unbounded";
  468. element.Name = element_qname.Name;
  469. KnownTypes.Add (element_type);
  470. SerializationMap map = KnownTypes.FindUserMap (element_type);
  471. if (map != null) {// non-primitive type
  472. map.GetSchemaType (schemas, generated_schema_types);
  473. element.IsNillable = true;
  474. }
  475. element.SchemaTypeName = element_qname;
  476. sequence.Items.Add (element);
  477. complex_type.Particle = sequence;
  478. XmlSchema schema = GetSchema (schemas, XmlName.Namespace);
  479. schema.Items.Add (complex_type);
  480. schema.Items.Add (GetSchemaElement (XmlName, complex_type));
  481. schemas.Reprocess (schema);
  482. generated_schema_types [XmlName] = complex_type;
  483. return complex_type;
  484. }
  485. #endif
  486. }
  487. internal class SharedTypeMap : SerializationMap
  488. {
  489. public SharedTypeMap (
  490. Type type, QName qname, KnownTypeCollection knownTypes)
  491. : base (type, qname, knownTypes)
  492. {
  493. Members = GetMembers (type, XmlName, false);
  494. }
  495. List<DataMemberInfo> GetMembers (Type type, QName qname, bool declared_only)
  496. {
  497. List<DataMemberInfo> data_members = new List<DataMemberInfo> ();
  498. int order = 0;
  499. BindingFlags flags = AllInstanceFlags;
  500. if (declared_only)
  501. flags |= BindingFlags.DeclaredOnly;
  502. foreach (FieldInfo fi in type.GetFields (flags)) {
  503. if (fi.GetCustomAttributes (
  504. typeof (NonSerializedAttribute),
  505. false).Length > 0)
  506. continue;
  507. if (fi.IsInitOnly)
  508. throw new InvalidDataContractException (String.Format ("DataMember field {0} must not be read-only.", fi));
  509. DataMemberAttribute dma = new DataMemberAttribute ();
  510. dma.Order = order++;
  511. data_members.Add (CreateDataMemberInfo (dma, fi, fi.FieldType));
  512. }
  513. return data_members;
  514. }
  515. public override List<DataMemberInfo> GetMembers ()
  516. {
  517. return GetMembers (RuntimeType, XmlName, true);
  518. }
  519. }
  520. internal class EnumMap : SerializationMap
  521. {
  522. List<EnumMemberInfo> enum_members;
  523. public EnumMap (
  524. Type type, QName qname, KnownTypeCollection knownTypes)
  525. : base (type, qname, knownTypes)
  526. {
  527. bool has_dc = false;
  528. object [] atts = RuntimeType.GetCustomAttributes (
  529. typeof (DataContractAttribute), false);
  530. if (atts.Length != 0)
  531. has_dc = true;
  532. enum_members = new List<EnumMemberInfo> ();
  533. BindingFlags flags = BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Static;
  534. foreach (FieldInfo fi in RuntimeType.GetFields (flags)) {
  535. string name = fi.Name;
  536. if (has_dc) {
  537. EnumMemberAttribute ema =
  538. GetEnumMemberAttribute (fi);
  539. if (ema == null)
  540. continue;
  541. if (ema.Value != null)
  542. name = ema.Value;
  543. }
  544. enum_members.Add (new EnumMemberInfo (name, fi.GetValue (null)));
  545. }
  546. }
  547. private EnumMemberAttribute GetEnumMemberAttribute (
  548. MemberInfo mi)
  549. {
  550. object [] atts = mi.GetCustomAttributes (
  551. typeof (EnumMemberAttribute), false);
  552. if (atts.Length == 0)
  553. return null;
  554. return (EnumMemberAttribute) atts [0];
  555. }
  556. #if !NET_2_1
  557. public override XmlSchemaType GetSchemaType (XmlSchemaSet schemas, Dictionary<QName, XmlSchemaType> generated_schema_types)
  558. {
  559. if (generated_schema_types.ContainsKey (XmlName))
  560. return generated_schema_types [XmlName];
  561. XmlSchemaSimpleType simpleType = new XmlSchemaSimpleType ();
  562. simpleType.Name = XmlName.Name;
  563. XmlSchemaSimpleTypeRestriction simpleRestriction = new XmlSchemaSimpleTypeRestriction ();
  564. simpleType.Content = simpleRestriction;
  565. simpleRestriction.BaseTypeName = new XmlQualifiedName ("string", XmlSchema.Namespace);
  566. foreach (EnumMemberInfo emi in enum_members) {
  567. XmlSchemaEnumerationFacet e = new XmlSchemaEnumerationFacet ();
  568. e.Value = emi.XmlName;
  569. simpleRestriction.Facets.Add (e);
  570. }
  571. generated_schema_types [XmlName] = simpleType;
  572. XmlSchema schema = GetSchema (schemas, XmlName.Namespace);
  573. XmlSchemaElement element = GetSchemaElement (XmlName, simpleType);
  574. element.IsNillable = true;
  575. schema.Items.Add (simpleType);
  576. schema.Items.Add (element);
  577. return simpleType;
  578. }
  579. #endif
  580. public override void Serialize (object graph,
  581. XmlFormatterSerializer serializer)
  582. {
  583. foreach (EnumMemberInfo emi in enum_members) {
  584. if (Enum.Equals (emi.Value, graph)) {
  585. serializer.Writer.WriteString (emi.XmlName);
  586. return;
  587. }
  588. }
  589. throw new SerializationException (String.Format (
  590. "Enum value '{0}' is invalid for type '{1}' and cannot be serialized.", graph, RuntimeType));
  591. }
  592. public override object DeserializeContent (XmlReader reader,
  593. XmlFormatterDeserializer deserializer)
  594. {
  595. string value = reader.NodeType != XmlNodeType.Text ? String.Empty : reader.ReadContentAsString ();
  596. if (value != String.Empty) {
  597. foreach (EnumMemberInfo emi in enum_members)
  598. if (emi.XmlName == value)
  599. return emi.Value;
  600. }
  601. throw new SerializationException (String.Format (
  602. "Enum value '{0}' is invalid for type '{1}' and cannot be deserialized.", value, RuntimeType));
  603. }
  604. }
  605. internal struct EnumMemberInfo
  606. {
  607. public readonly string XmlName;
  608. public readonly object Value;
  609. public EnumMemberInfo (string name, object value)
  610. {
  611. XmlName = name;
  612. Value = value;
  613. }
  614. }
  615. internal class DataMemberInfo //: KeyValuePair<int, MemberInfo>
  616. {
  617. public readonly int Order;
  618. public readonly bool IsRequired;
  619. public readonly string XmlName;
  620. public readonly MemberInfo Member;
  621. public readonly string XmlNamespace;
  622. public readonly string XmlRootNamespace;
  623. public readonly Type MemberType;
  624. public DataMemberInfo (MemberInfo member, DataMemberAttribute dma, string rootNamespce, string ns)
  625. {
  626. if (dma == null)
  627. throw new ArgumentNullException ("dma");
  628. Order = dma.Order;
  629. Member = member;
  630. IsRequired = dma.IsRequired;
  631. XmlName = dma.Name != null ? dma.Name : member.Name;
  632. XmlNamespace = ns;
  633. XmlRootNamespace = rootNamespce;
  634. if (Member is FieldInfo)
  635. MemberType = ((FieldInfo) Member).FieldType;
  636. else
  637. MemberType = ((PropertyInfo) Member).PropertyType;
  638. }
  639. public class DataMemberInfoComparer : IComparer<DataMemberInfo>
  640. , IComparer // see bug #76361
  641. {
  642. public static readonly DataMemberInfoComparer Instance
  643. = new DataMemberInfoComparer ();
  644. private DataMemberInfoComparer () {}
  645. public int Compare (object o1, object o2)
  646. {
  647. return Compare ((DataMemberInfo) o1,
  648. (DataMemberInfo) o2);
  649. }
  650. public int Compare (DataMemberInfo d1, DataMemberInfo d2)
  651. {
  652. if (d1.Order == -1 || d2.Order == -1)
  653. return String.CompareOrdinal (d1.XmlName, d2.XmlName);
  654. return d1.Order - d2.Order;
  655. }
  656. }
  657. }
  658. }
  659. #endif