PageRenderTime 45ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/mcs/class/System.Runtime.Serialization/System.Runtime.Serialization/SerializationMap.cs

https://bitbucket.org/danipen/mono
C# | 1120 lines | 892 code | 146 blank | 82 comment | 228 complexity | 4ebde0e623db32a0f87947a47c185658 MD5 | raw file
Possible License(s): Unlicense, Apache-2.0, LGPL-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0
  1. //
  2. // SerializationMap.cs
  3. //
  4. // Author:
  5. // Atsushi Enomoto <atsushi@ximian.com>
  6. // Ankit Jain <JAnkit@novell.com>
  7. // Duncan Mak (duncan@ximian.com)
  8. // Eyal Alaluf (eyala@mainsoft.com)
  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.Linq;
  38. using System.Reflection;
  39. using System.Xml;
  40. using System.Xml.Schema;
  41. using System.Xml.Serialization;
  42. using QName = System.Xml.XmlQualifiedName;
  43. namespace System.Runtime.Serialization
  44. {
  45. /*
  46. XmlFormatter implementation design inference:
  47. type definitions:
  48. - No XML Schema types are directly used. There are some maps from
  49. xs:blahType to ms:blahType where the namespaceURI for prefix "ms" is
  50. "http://schemas.microsoft.com/2003/10/Serialization/" .
  51. serializable types:
  52. - An object being serialized 1) must be of type System.Object, or
  53. 2) must be null, or 3) must have either a [DataContract] attribute
  54. or a [Serializable] attribute to be serializable.
  55. - When the object is either of type System.Object or null, then the
  56. XML type is "anyType".
  57. - When the object is [Serializable], then the runtime-serialization
  58. compatible object graph is written.
  59. - Otherwise the serialization is based on contract attributes.
  60. ([Serializable] takes precedence).
  61. type derivation:
  62. - For type A to be serializable, the base type B of A must be
  63. serializable.
  64. - If a type which is [Serializable] and whose base type has a
  65. [DataContract], then for base type members [DataContract] is taken.
  66. - It is vice versa i.e. if the base type is [Serializable] and the
  67. derived type has a [DataContract], then [Serializable] takes place
  68. for base members.
  69. known type collection:
  70. - It internally manages mapping store keyed by contract QNames.
  71. KnownTypeCollection.Add() checks if the same QName contract already
  72. exists (and raises InvalidOperationException if required).
  73. */
  74. internal abstract partial class SerializationMap
  75. {
  76. public const BindingFlags AllInstanceFlags =
  77. BindingFlags.Public | BindingFlags.NonPublic |
  78. BindingFlags.Instance;
  79. public readonly KnownTypeCollection KnownTypes;
  80. public readonly Type RuntimeType;
  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 == null)
  94. qname = new QName (qname.Name,
  95. KnownTypeCollection.DefaultClrNamespaceBase + type.Namespace);
  96. XmlName = qname;
  97. Members = new List<DataMemberInfo> ();
  98. foreach (var mi in type.GetMethods (AllInstanceFlags)) {
  99. if (mi.GetCustomAttributes (typeof (OnDeserializingAttribute), false).Length > 0)
  100. OnDeserializing = mi;
  101. else if (mi.GetCustomAttributes (typeof (OnDeserializedAttribute), false).Length > 0)
  102. OnDeserialized = mi;
  103. }
  104. }
  105. public MethodInfo OnDeserializing { get; set; }
  106. public MethodInfo OnDeserialized { get; set; }
  107. public virtual bool OutputXsiType {
  108. get { return true; }
  109. }
  110. public QName XmlName { get; set; }
  111. public abstract bool IsContractAllowedType { get; }
  112. protected void HandleId (XmlReader reader, XmlFormatterDeserializer deserializer, object instance)
  113. {
  114. HandleId (reader.GetAttribute ("Id", KnownTypeCollection.MSSimpleNamespace), deserializer, instance);
  115. }
  116. protected void HandleId (string id, XmlFormatterDeserializer deserializer, object instance)
  117. {
  118. if (id != null)
  119. deserializer.References.Add (id, instance);
  120. }
  121. public CollectionDataContractAttribute GetCollectionDataContractAttribute (Type type)
  122. {
  123. object [] atts = type.GetCustomAttributes (
  124. typeof (CollectionDataContractAttribute), false);
  125. return atts.Length == 0 ? null : (CollectionDataContractAttribute) atts [0];
  126. }
  127. public DataMemberAttribute GetDataMemberAttribute (
  128. MemberInfo mi)
  129. {
  130. object [] atts = mi.GetCustomAttributes (
  131. typeof (DataMemberAttribute), false);
  132. if (atts.Length == 0)
  133. return null;
  134. return (DataMemberAttribute) atts [0];
  135. }
  136. bool IsPrimitive (Type type)
  137. {
  138. return (Type.GetTypeCode (type) != TypeCode.Object || type == typeof (object));
  139. }
  140. //Returns list of data members for this type ONLY
  141. public virtual List<DataMemberInfo> GetMembers ()
  142. {
  143. throw new NotImplementedException (String.Format ("Implement me for {0}", this));
  144. }
  145. #if !NET_2_1
  146. protected XmlSchemaElement GetSchemaElement (QName qname, XmlSchemaType schemaType)
  147. {
  148. XmlSchemaElement schemaElement = new XmlSchemaElement ();
  149. schemaElement.Name = qname.Name;
  150. schemaElement.SchemaTypeName = qname;
  151. if (schemaType is XmlSchemaComplexType)
  152. schemaElement.IsNillable = true;
  153. return schemaElement;
  154. }
  155. protected XmlSchema GetSchema (XmlSchemaSet schemas, string ns)
  156. {
  157. ICollection colln = schemas.Schemas (ns);
  158. if (colln.Count > 0) {
  159. if (colln.Count > 1)
  160. throw new Exception (String.Format (
  161. "More than 1 schema for namespace '{0}' found.", ns));
  162. foreach (object o in colln)
  163. //return colln [0]
  164. return (o as XmlSchema);
  165. }
  166. XmlSchema schema = new XmlSchema ();
  167. schema.TargetNamespace = ns;
  168. schema.ElementFormDefault = XmlSchemaForm.Qualified;
  169. schemas.Add (schema);
  170. return schema;
  171. }
  172. protected XmlQualifiedName GetQualifiedName (Type type)
  173. {
  174. if (qname_table.ContainsKey (type))
  175. return qname_table [type];
  176. QName qname = KnownTypes.GetQName (type);
  177. if (qname.Namespace == KnownTypeCollection.MSSimpleNamespace)
  178. qname = new QName (qname.Name, XmlSchema.Namespace);
  179. qname_table [type] = qname;
  180. return qname;
  181. }
  182. #endif
  183. public virtual void Serialize (object graph,
  184. XmlFormatterSerializer serializer)
  185. {
  186. string label;
  187. if (serializer.TrySerializeAsReference (IsReference, graph, out label))
  188. return;
  189. else if (serializer.SerializingObjects.Contains (graph))
  190. throw new SerializationException (String.Format ("Circular reference of an object in the object graph was found: '{0}' of type {1}", graph, graph.GetType ()));
  191. serializer.SerializingObjects.Add (graph);
  192. if (label != null)
  193. serializer.Writer.WriteAttributeString ("z", "Id", KnownTypeCollection.MSSimpleNamespace, label);
  194. SerializeNonReference (graph, serializer);
  195. serializer.SerializingObjects.Remove (graph);
  196. }
  197. public virtual void SerializeNonReference (object graph,
  198. XmlFormatterSerializer serializer)
  199. {
  200. foreach (DataMemberInfo dmi in Members) {
  201. FieldInfo fi = dmi.Member as FieldInfo;
  202. PropertyInfo pi = fi == null ?
  203. (PropertyInfo) dmi.Member : null;
  204. Type type = fi != null ?
  205. fi.FieldType : pi.PropertyType;
  206. object value = fi != null ?
  207. fi.GetValue (graph) :
  208. pi.GetValue (graph, null);
  209. serializer.WriteStartElement (dmi.XmlName, dmi.XmlRootNamespace, dmi.XmlNamespace);
  210. serializer.Serialize (type, value);
  211. serializer.WriteEndElement ();
  212. }
  213. }
  214. public virtual object DeserializeObject (XmlReader reader, XmlFormatterDeserializer deserializer)
  215. {
  216. bool isEmpty = reader.IsEmptyElement;
  217. string id = reader.GetAttribute ("Id", KnownTypeCollection.MSSimpleNamespace);
  218. reader.ReadStartElement ();
  219. reader.MoveToContent ();
  220. object res;
  221. if (isEmpty)
  222. res = DeserializeEmptyContent (reader, deserializer, id);
  223. else
  224. res = DeserializeContent (reader, deserializer, id);
  225. reader.MoveToContent ();
  226. if (!isEmpty && reader.NodeType == XmlNodeType.EndElement)
  227. reader.ReadEndElement ();
  228. else if (!isEmpty && !reader.EOF && reader.NodeType != XmlNodeType.EndElement) {
  229. var li = reader as IXmlLineInfo;
  230. throw new SerializationException (String.Format ("Deserializing type '{3}'. Expecting state 'EndElement'. Encountered state '{0}' with name '{1}' with namespace '{2}'.{4}",
  231. reader.NodeType,
  232. reader.Name,
  233. reader.NamespaceURI,
  234. RuntimeType.FullName,
  235. li != null && li.HasLineInfo () ? String.Format (" {0}({1},{2})", reader.BaseURI, li.LineNumber, li.LinePosition) : String.Empty));
  236. }
  237. return res;
  238. }
  239. // This is sort of hack. The argument reader already moved ahead of
  240. // the actual empty element.It's just for historical consistency.
  241. public virtual object DeserializeEmptyContent (XmlReader reader,
  242. XmlFormatterDeserializer deserializer, string id)
  243. {
  244. return DeserializeContent (reader, deserializer, id, true);
  245. }
  246. public virtual object DeserializeContent (XmlReader reader,
  247. XmlFormatterDeserializer deserializer, string id)
  248. {
  249. return DeserializeContent (reader, deserializer, id, false);
  250. }
  251. object DeserializeContent (XmlReader reader, XmlFormatterDeserializer deserializer, string id, bool empty)
  252. {
  253. object instance = FormatterServices.GetUninitializedObject (RuntimeType);
  254. HandleId (id, deserializer, instance);
  255. if (OnDeserializing != null)
  256. OnDeserializing.Invoke (instance, new object [] {new StreamingContext (StreamingContextStates.All)});
  257. int depth = reader.NodeType == XmlNodeType.None ? reader.Depth : reader.Depth - 1;
  258. bool [] filled = new bool [Members.Count];
  259. bool [] nsmatched = new bool [Members.Count];
  260. int memberInd = -1, ordered = -1;
  261. while (!empty && reader.NodeType == XmlNodeType.Element && reader.Depth > depth) {
  262. DataMemberInfo dmi = null;
  263. int i = 0;
  264. bool nsmatchedOne = false;
  265. for (; i < Members.Count; i++) { // unordered
  266. if (Members [i].Order >= 0)
  267. break;
  268. if (reader.LocalName == Members [i].XmlName) {
  269. memberInd = i;
  270. dmi = Members [i];
  271. nsmatchedOne = (dmi.XmlRootNamespace == null || reader.NamespaceURI == dmi.XmlRootNamespace);
  272. if (nsmatchedOne)
  273. break;
  274. }
  275. }
  276. for (i = Math.Max (i, ordered); i < Members.Count; i++) { // ordered
  277. if (dmi != null)
  278. break;
  279. if (reader.LocalName == Members [i].XmlName) {
  280. ordered = i;
  281. memberInd = i;
  282. dmi = Members [i];
  283. nsmatchedOne = (dmi.XmlRootNamespace == null || reader.NamespaceURI == dmi.XmlRootNamespace);
  284. if (nsmatchedOne)
  285. break;
  286. }
  287. }
  288. if (dmi == null) {
  289. reader.Skip ();
  290. reader.MoveToContent ();
  291. continue;
  292. }
  293. if (filled [memberInd] && nsmatched [memberInd]) {
  294. // The strictly-corresponding member (i.e. that matches namespace URI too, not only local name) already exists, so skip this element.
  295. reader.Skip ();
  296. reader.MoveToContent ();
  297. continue;
  298. }
  299. nsmatched [memberInd] = nsmatchedOne;
  300. SetValue (dmi, instance, deserializer.Deserialize (dmi.MemberType, reader));
  301. filled [memberInd] = true;
  302. reader.MoveToContent ();
  303. }
  304. for (int i = 0; i < Members.Count; i++)
  305. if (!filled [i] && Members [i].IsRequired)
  306. throw MissingRequiredMember (Members [i], reader);
  307. if (OnDeserialized != null)
  308. OnDeserialized.Invoke (instance, new object [] {new StreamingContext (StreamingContextStates.All)});
  309. return instance;
  310. }
  311. // For now it could be private.
  312. protected Exception MissingRequiredMember (DataMemberInfo dmi, XmlReader reader)
  313. {
  314. var li = reader as IXmlLineInfo;
  315. return new ArgumentException (String.Format ("Data contract member {0} for the type {1} is required, but missing in the input XML.{2}",
  316. new QName (dmi.XmlName, dmi.XmlNamespace),
  317. RuntimeType,
  318. li != null && li.HasLineInfo () ? String.Format (" {0}({1},{2})", reader.BaseURI, li.LineNumber, li.LinePosition) : null));
  319. }
  320. // For now it could be private.
  321. protected void SetValue (DataMemberInfo dmi, object obj, object value)
  322. {
  323. try {
  324. if (dmi.Member is PropertyInfo)
  325. ((PropertyInfo) dmi.Member).SetValue (obj, value, null);
  326. else
  327. ((FieldInfo) dmi.Member).SetValue (obj, value);
  328. } catch (Exception ex) {
  329. throw new InvalidOperationException (String.Format ("Failed to set value of type {0} for property {1}", value != null ? value.GetType () : null, dmi.Member), ex);
  330. }
  331. }
  332. protected DataMemberInfo CreateDataMemberInfo (DataMemberAttribute dma, MemberInfo mi, Type memberType, string ownerNamespace)
  333. {
  334. KnownTypes.Add (memberType);
  335. QName qname = KnownTypes.GetQName (memberType);
  336. if (KnownTypeCollection.GetPrimitiveTypeFromName (qname) != null)
  337. return new DataMemberInfo (mi, dma, ownerNamespace, null);
  338. else
  339. return new DataMemberInfo (mi, dma, ownerNamespace, qname.Namespace);
  340. }
  341. }
  342. internal partial class XmlSerializableMap : SerializationMap
  343. {
  344. public override bool IsContractAllowedType { get { return true; } }
  345. public XmlSerializableMap (Type type, QName qname, KnownTypeCollection knownTypes)
  346. : base (type, qname, knownTypes)
  347. {
  348. }
  349. public override void Serialize (object graph, XmlFormatterSerializer serializer)
  350. {
  351. IXmlSerializable ixs = graph as IXmlSerializable;
  352. if (ixs == null)
  353. //FIXME: Throw what exception here?
  354. throw new SerializationException ();
  355. ixs.WriteXml (serializer.Writer);
  356. }
  357. public override object DeserializeObject (XmlReader reader, XmlFormatterDeserializer deserializer)
  358. {
  359. #if NET_2_1
  360. IXmlSerializable ixs = (IXmlSerializable) Activator.CreateInstance (RuntimeType);
  361. #else
  362. IXmlSerializable ixs = (IXmlSerializable) Activator.CreateInstance (RuntimeType, true);
  363. #endif
  364. HandleId (reader, deserializer, ixs);
  365. ixs.ReadXml (reader);
  366. return ixs;
  367. }
  368. }
  369. internal partial class SharedContractMap : SerializationMap
  370. {
  371. public SharedContractMap (
  372. Type type, QName qname, KnownTypeCollection knownTypes)
  373. : base (type, qname, knownTypes)
  374. {
  375. }
  376. public override bool IsContractAllowedType { get { return true; } }
  377. internal void Initialize ()
  378. {
  379. Type type = RuntimeType;
  380. List <DataMemberInfo> members;
  381. object [] atts = type.GetCustomAttributes (
  382. typeof (DataContractAttribute), false);
  383. IsReference = atts.Length > 0 ? (((DataContractAttribute) atts [0]).IsReference) : false;
  384. while (type != null) {
  385. members = GetMembers (type);
  386. members.Sort (DataMemberInfo.DataMemberInfoComparer.Instance);
  387. Members.InsertRange (0, members);
  388. members.Clear ();
  389. type = type.BaseType;
  390. }
  391. }
  392. List<DataMemberInfo> GetMembers (Type type)
  393. {
  394. List<DataMemberInfo> data_members = new List<DataMemberInfo> ();
  395. BindingFlags flags = AllInstanceFlags | BindingFlags.DeclaredOnly;
  396. foreach (PropertyInfo pi in type.GetProperties (flags)) {
  397. DataMemberAttribute dma =
  398. GetDataMemberAttribute (pi);
  399. if (dma == null)
  400. continue;
  401. KnownTypes.Add (pi.PropertyType);
  402. var map = KnownTypes.FindUserMap (pi.PropertyType);
  403. if (!pi.CanRead || (!pi.CanWrite && !(map is ICollectionTypeMap)))
  404. throw new InvalidDataContractException (String.Format (
  405. "DataMember property '{0}' on type '{1}' must have both getter and setter.", pi, pi.DeclaringType));
  406. data_members.Add (CreateDataMemberInfo (dma, pi, pi.PropertyType, KnownTypeCollection.GetStaticQName (pi.DeclaringType).Namespace));
  407. }
  408. foreach (FieldInfo fi in type.GetFields (flags)) {
  409. DataMemberAttribute dma =
  410. GetDataMemberAttribute (fi);
  411. if (dma == null)
  412. continue;
  413. data_members.Add (CreateDataMemberInfo (dma, fi, fi.FieldType, KnownTypeCollection.GetStaticQName (fi.DeclaringType).Namespace));
  414. }
  415. return data_members;
  416. }
  417. public override List<DataMemberInfo> GetMembers ()
  418. {
  419. return Members;
  420. }
  421. }
  422. internal partial class DefaultTypeMap : SerializationMap
  423. {
  424. public DefaultTypeMap (Type type, KnownTypeCollection knownTypes)
  425. : base (type, KnownTypeCollection.GetStaticQName (type), knownTypes)
  426. {
  427. }
  428. public override bool IsContractAllowedType { get { return false; } }
  429. internal void Initialize ()
  430. {
  431. Members.AddRange (GetDefaultMembers ());
  432. }
  433. List<DataMemberInfo> GetDefaultMembers ()
  434. {
  435. var l = new List<DataMemberInfo> ();
  436. foreach (var mi in RuntimeType.GetMembers ()) {
  437. Type mt = null;
  438. FieldInfo fi = mi as FieldInfo;
  439. mt = fi == null ? null : fi.FieldType;
  440. PropertyInfo pi = mi as PropertyInfo;
  441. if (pi != null && pi.CanRead && pi.CanWrite && pi.GetIndexParameters ().Length == 0)
  442. mt = pi.PropertyType;
  443. if (mt == null)
  444. continue;
  445. if (mi.GetCustomAttributes (typeof (IgnoreDataMemberAttribute), false).Length != 0)
  446. continue;
  447. string ns = KnownTypeCollection.GetStaticQName (mi.DeclaringType).Namespace;
  448. l.Add (CreateDataMemberInfo (new DataMemberAttribute (), mi, mt, ns));
  449. }
  450. l.Sort (DataMemberInfo.DataMemberInfoComparer.Instance);
  451. return l;
  452. }
  453. }
  454. // FIXME: it still needs to consider KeyName/ValueName
  455. // (especially Dictionary collection is not likely considered yet.)
  456. internal partial class CollectionContractTypeMap : CollectionTypeMap
  457. {
  458. CollectionDataContractAttribute a;
  459. public CollectionContractTypeMap (
  460. Type type, CollectionDataContractAttribute a, Type elementType,
  461. QName qname, KnownTypeCollection knownTypes)
  462. : base (type, elementType, qname, knownTypes)
  463. {
  464. this.a = a;
  465. IsReference = a.IsReference;
  466. if (!String.IsNullOrEmpty (a.ItemName))
  467. element_qname = new XmlQualifiedName (a.ItemName, a.Namespace ?? CurrentNamespace);
  468. }
  469. internal override string CurrentNamespace {
  470. get { return XmlName.Namespace; }
  471. }
  472. public override bool IsContractAllowedType { get { return true; } }
  473. }
  474. internal interface ICollectionTypeMap
  475. {
  476. }
  477. internal partial class CollectionTypeMap : SerializationMap, ICollectionTypeMap
  478. {
  479. Type element_type;
  480. internal QName element_qname;
  481. MethodInfo add_method;
  482. public CollectionTypeMap (
  483. Type type, Type elementType,
  484. QName qname, KnownTypeCollection knownTypes)
  485. : base (type, qname, knownTypes)
  486. {
  487. element_type = elementType;
  488. element_qname = KnownTypes.GetQName (element_type);
  489. var icoll = GetGenericCollectionInterface (RuntimeType);
  490. if (icoll != null) {
  491. if (RuntimeType.IsInterface) {
  492. add_method = RuntimeType.GetMethod ("Add", icoll.GetGenericArguments ());
  493. } else {
  494. var imap = RuntimeType.GetInterfaceMap (icoll);
  495. for (int i = 0; i < imap.InterfaceMethods.Length; i++)
  496. if (imap.InterfaceMethods [i].Name == "Add") {
  497. add_method = imap.TargetMethods [i];
  498. break;
  499. }
  500. if (add_method == null)
  501. add_method = type.GetMethod ("Add", icoll.GetGenericArguments ());
  502. }
  503. }
  504. }
  505. static Type GetGenericCollectionInterface (Type type)
  506. {
  507. foreach (var iface in type.GetInterfacesOrSelfInterface ())
  508. if (iface.IsGenericType && iface.GetGenericTypeDefinition () == typeof (IEnumerable<>))
  509. return iface;
  510. return null;
  511. }
  512. public override bool IsContractAllowedType { get { return false; } }
  513. public override bool OutputXsiType {
  514. get { return false; }
  515. }
  516. internal virtual string CurrentNamespace {
  517. get {
  518. string ns = element_qname.Namespace;
  519. if (ns == KnownTypeCollection.MSSimpleNamespace)
  520. ns = KnownTypeCollection.MSArraysNamespace;
  521. return ns;
  522. }
  523. }
  524. public override void SerializeNonReference (object graph,
  525. XmlFormatterSerializer serializer)
  526. {
  527. // output item xmlns in advance so that it does not result in excessive xmlns overwrites.
  528. if (XmlName.Namespace != element_qname.Namespace && element_qname.Namespace != KnownTypeCollection.MSSimpleNamespace)
  529. serializer.Writer.WriteXmlnsAttribute (null, element_qname.Namespace);
  530. foreach (object o in (IEnumerable) graph) {
  531. serializer.WriteStartElement (element_qname.Name, XmlName.Namespace, CurrentNamespace);
  532. serializer.Serialize (element_type, o);
  533. serializer.WriteEndElement ();
  534. }
  535. }
  536. object CreateInstance ()
  537. {
  538. if (RuntimeType.IsArray)
  539. return new ArrayList ();
  540. if (RuntimeType.IsInterface) {
  541. var icoll = GetGenericCollectionInterface (RuntimeType);
  542. if (icoll != null)
  543. return Activator.CreateInstance (typeof (List<>).MakeGenericType (RuntimeType.GetGenericArguments () [0])); // List<T>
  544. else // non-generic
  545. return new ArrayList ();
  546. }
  547. #if NET_2_1 // FIXME: is it fine?
  548. return Activator.CreateInstance (RuntimeType);
  549. #else
  550. return Activator.CreateInstance (RuntimeType, true);
  551. #endif
  552. }
  553. public override object DeserializeEmptyContent (XmlReader reader, XmlFormatterDeserializer deserializer, string id)
  554. {
  555. var instance = CreateInstance ();
  556. HandleId (id, deserializer, instance);
  557. if (OnDeserializing != null)
  558. OnDeserializing.Invoke (instance, new object [] {new StreamingContext (StreamingContextStates.All)});
  559. try {
  560. if (RuntimeType.IsArray)
  561. return ((ArrayList)instance).ToArray (element_type);
  562. else
  563. return instance;
  564. } finally {
  565. if (OnDeserialized != null)
  566. OnDeserialized.Invoke (instance, new object [] {new StreamingContext (StreamingContextStates.All)});
  567. }
  568. }
  569. public override object DeserializeContent (XmlReader reader, XmlFormatterDeserializer deserializer, string id)
  570. {
  571. object instance = CreateInstance ();
  572. HandleId (id, deserializer, instance);
  573. if (OnDeserializing != null)
  574. OnDeserializing.Invoke (instance, new object [] {new StreamingContext (StreamingContextStates.All)});
  575. int depth = reader.NodeType == XmlNodeType.None ? reader.Depth : reader.Depth - 1;
  576. while (reader.NodeType == XmlNodeType.Element && reader.Depth > depth) {
  577. object elem = deserializer.Deserialize (element_type, reader);
  578. if (instance is IList)
  579. ((IList)instance).Add (elem);
  580. else if (add_method != null)
  581. add_method.Invoke (instance, new object [] {elem});
  582. else
  583. throw new NotImplementedException (String.Format ("Type {0} is not supported", RuntimeType));
  584. reader.MoveToContent ();
  585. }
  586. try {
  587. if (RuntimeType.IsArray)
  588. return ((ArrayList)instance).ToArray (element_type);
  589. return instance;
  590. } finally {
  591. if (OnDeserialized != null)
  592. OnDeserialized.Invoke (instance, new object [] {new StreamingContext (StreamingContextStates.All)});
  593. }
  594. }
  595. public override List<DataMemberInfo> GetMembers ()
  596. {
  597. //Shouldn't come here at all!
  598. throw new NotImplementedException ();
  599. }
  600. }
  601. internal partial class DictionaryTypeMap : SerializationMap, ICollectionTypeMap
  602. {
  603. Type key_type, value_type;
  604. QName item_qname, key_qname, value_qname;
  605. MethodInfo add_method;
  606. CollectionDataContractAttribute a;
  607. public DictionaryTypeMap (
  608. Type type, CollectionDataContractAttribute a, KnownTypeCollection knownTypes)
  609. : base (type, QName.Empty, knownTypes)
  610. {
  611. this.a = a;
  612. key_type = typeof (object);
  613. value_type = typeof (object);
  614. var idic = GetGenericDictionaryInterface (RuntimeType);
  615. if (idic != null) {
  616. var imap = RuntimeType.GetInterfaceMap (idic);
  617. for (int i = 0; i < imap.InterfaceMethods.Length; i++)
  618. if (imap.InterfaceMethods [i].Name == "Add") {
  619. add_method = imap.TargetMethods [i];
  620. break;
  621. }
  622. var argtypes = idic.GetGenericArguments();
  623. key_type = argtypes [0];
  624. value_type = argtypes [1];
  625. if (add_method == null)
  626. add_method = type.GetMethod ("Add", argtypes);
  627. }
  628. XmlName = GetDictionaryQName ();
  629. item_qname = GetItemQName ();
  630. key_qname = GetKeyQName ();
  631. value_qname = GetValueQName ();
  632. }
  633. static Type GetGenericDictionaryInterface (Type type)
  634. {
  635. foreach (var iface in type.GetInterfacesOrSelfInterface ())
  636. if (iface.IsGenericType && iface.GetGenericTypeDefinition () == typeof (IDictionary<,>))
  637. return iface;
  638. return null;
  639. }
  640. string ContractNamespace {
  641. get { return a != null && !String.IsNullOrEmpty (a.Namespace) ? a.Namespace : KnownTypeCollection.MSArraysNamespace; }
  642. }
  643. public override bool IsContractAllowedType { get { return a != null; } }
  644. public Type KeyType { get { return key_type; } }
  645. public Type ValueType { get { return value_type; } }
  646. internal virtual QName GetDictionaryQName ()
  647. {
  648. string name = a != null ? a.Name : null;
  649. string ns = a != null ? a.Namespace : null;
  650. if (RuntimeType.IsGenericType && RuntimeType.GetGenericTypeDefinition () != typeof (Dictionary<,>))
  651. name = name ?? KnownTypeCollection.GetDefaultName (RuntimeType);
  652. else
  653. name = "ArrayOf" + GetItemQName ().Name;
  654. ns = ns ?? KnownTypeCollection.MSArraysNamespace;
  655. return new QName (name, ns);
  656. }
  657. internal virtual QName GetItemQName ()
  658. {
  659. string name = a != null ? a.ItemName : null;
  660. string ns = a != null ? a.Namespace : null;
  661. name = name ?? "KeyValueOf" + KnownTypes.GetQName (key_type).Name + KnownTypes.GetQName (value_type).Name;
  662. ns = ns ?? (a != null ? ContractNamespace : KnownTypeCollection.MSArraysNamespace);
  663. return new QName (name, ns);
  664. }
  665. internal virtual QName GetKeyQName ()
  666. {
  667. string name = a != null ? a.KeyName : null;
  668. string ns = a != null ? a.Namespace : null;
  669. name = name ?? "Key";
  670. ns = ns ?? (a != null ? ContractNamespace : KnownTypeCollection.MSArraysNamespace);
  671. return new QName (name, ns);
  672. }
  673. internal virtual QName GetValueQName ()
  674. {
  675. string name = a != null ? a.ValueName : null;
  676. string ns = a != null ? a.Namespace : null;
  677. name = name ?? "Value";
  678. ns = ns ?? (a != null ? ContractNamespace : KnownTypeCollection.MSArraysNamespace);
  679. return new QName (name, ns);
  680. }
  681. internal virtual string CurrentNamespace {
  682. get {
  683. string ns = item_qname.Namespace;
  684. if (ns == KnownTypeCollection.MSSimpleNamespace)
  685. ns = KnownTypeCollection.MSArraysNamespace;
  686. return ns;
  687. }
  688. }
  689. Type pair_type;
  690. PropertyInfo pair_key_property, pair_value_property;
  691. public override void SerializeNonReference (object graph,
  692. XmlFormatterSerializer serializer)
  693. {
  694. if (add_method != null) { // generic
  695. if (pair_type == null) {
  696. pair_type = typeof (KeyValuePair<,>).MakeGenericType (add_method.DeclaringType.GetGenericArguments ());
  697. pair_key_property = pair_type.GetProperty ("Key");
  698. pair_value_property = pair_type.GetProperty ("Value");
  699. }
  700. foreach (object p in (IEnumerable) graph) {
  701. serializer.WriteStartElement (item_qname.Name, item_qname.Namespace, CurrentNamespace);
  702. serializer.WriteStartElement (key_qname.Name, key_qname.Namespace, CurrentNamespace);
  703. serializer.Serialize (pair_key_property.PropertyType, pair_key_property.GetValue (p, null));
  704. serializer.WriteEndElement ();
  705. serializer.WriteStartElement (value_qname.Name, value_qname.Namespace, CurrentNamespace);
  706. serializer.Serialize (pair_value_property.PropertyType, pair_value_property.GetValue (p, null));
  707. serializer.WriteEndElement ();
  708. serializer.WriteEndElement ();
  709. }
  710. } else { // non-generic
  711. foreach (DictionaryEntry p in (IEnumerable) graph) {
  712. serializer.WriteStartElement (item_qname.Name, item_qname.Namespace, CurrentNamespace);
  713. serializer.WriteStartElement (key_qname.Name, key_qname.Namespace, CurrentNamespace);
  714. serializer.Serialize (key_type, p.Key);
  715. serializer.WriteEndElement ();
  716. serializer.WriteStartElement (value_qname.Name, value_qname.Namespace, CurrentNamespace);
  717. serializer.Serialize (value_type, p.Value);
  718. serializer.WriteEndElement ();
  719. serializer.WriteEndElement ();
  720. }
  721. }
  722. }
  723. object CreateInstance ()
  724. {
  725. if (RuntimeType.IsInterface) {
  726. if (RuntimeType.IsGenericType && Array.IndexOf (RuntimeType.GetGenericTypeDefinition ().GetInterfaces (), typeof (IDictionary<,>)) >= 0) {
  727. var gargs = RuntimeType.GetGenericArguments ();
  728. return Activator.CreateInstance (typeof (Dictionary<,>).MakeGenericType (gargs [0], gargs [1])); // Dictionary<T>
  729. }
  730. else // non-generic
  731. return new Hashtable ();
  732. }
  733. #if NET_2_1 // FIXME: is it fine?
  734. return Activator.CreateInstance (RuntimeType);
  735. #else
  736. return Activator.CreateInstance (RuntimeType, true);
  737. #endif
  738. }
  739. public override object DeserializeEmptyContent (XmlReader reader, XmlFormatterDeserializer deserializer, string id)
  740. {
  741. object instance = CreateInstance ();
  742. HandleId (id, deserializer, instance);
  743. return instance;
  744. }
  745. public override object DeserializeContent (XmlReader reader, XmlFormatterDeserializer deserializer, string id)
  746. {
  747. object instance = CreateInstance ();
  748. HandleId (id, deserializer, instance);
  749. int depth = reader.NodeType == XmlNodeType.None ? reader.Depth : reader.Depth - 1;
  750. while (reader.NodeType == XmlNodeType.Element && reader.Depth > depth) {
  751. if (reader.IsEmptyElement)
  752. throw new XmlException (String.Format ("Unexpected empty element for dictionary entry: name {0}", reader.Name));
  753. // FIXME: sloppy parsing
  754. reader.ReadStartElement ();// item_qname.Name, item_qname.Namespace);
  755. reader.MoveToContent ();
  756. object key = deserializer.Deserialize (key_type, reader);
  757. reader.MoveToContent ();
  758. object val = deserializer.Deserialize (value_type, reader);
  759. reader.MoveToContent ();
  760. reader.ReadEndElement (); // of pair
  761. reader.MoveToContent ();
  762. if (instance is IDictionary)
  763. ((IDictionary)instance).Add (key, val);
  764. else if (add_method != null)
  765. add_method.Invoke (instance, new object [] {key, val});
  766. else
  767. throw new NotImplementedException (String.Format ("Type {0} is not supported", RuntimeType));
  768. }
  769. return instance;
  770. }
  771. public override List<DataMemberInfo> GetMembers ()
  772. {
  773. //Shouldn't come here at all!
  774. throw new NotImplementedException ();
  775. }
  776. }
  777. internal partial class SharedTypeMap : SerializationMap
  778. {
  779. public SharedTypeMap (
  780. Type type, QName qname, KnownTypeCollection knownTypes)
  781. : base (type, qname, knownTypes)
  782. {
  783. }
  784. public override bool IsContractAllowedType { get { return true; } }
  785. public void Initialize ()
  786. {
  787. Members = GetMembers (RuntimeType, XmlName, false);
  788. }
  789. List<DataMemberInfo> GetMembers (Type type, QName qname, bool declared_only)
  790. {
  791. List<DataMemberInfo> data_members = new List<DataMemberInfo> ();
  792. BindingFlags flags = AllInstanceFlags | BindingFlags.DeclaredOnly;
  793. for (Type t = type; t != null; t = t.BaseType) {
  794. foreach (FieldInfo fi in t.GetFields (flags)) {
  795. if (fi.GetCustomAttributes (
  796. typeof (NonSerializedAttribute),
  797. false).Length > 0)
  798. continue;
  799. if (fi.IsInitOnly)
  800. throw new InvalidDataContractException (String.Format ("DataMember field {0} must not be read-only.", fi));
  801. DataMemberAttribute dma = new DataMemberAttribute ();
  802. data_members.Add (CreateDataMemberInfo (dma, fi, fi.FieldType, KnownTypeCollection.GetStaticQName (fi.DeclaringType).Namespace));
  803. }
  804. }
  805. data_members.Sort (DataMemberInfo.DataMemberInfoComparer.Instance); // alphabetic order.
  806. return data_members;
  807. }
  808. // Does this make sense? I doubt.
  809. public override List<DataMemberInfo> GetMembers ()
  810. {
  811. return Members;
  812. //return GetMembers (RuntimeType, XmlName, true);
  813. }
  814. }
  815. internal partial class EnumMap : SerializationMap
  816. {
  817. List<EnumMemberInfo> enum_members;
  818. bool flag_attr;
  819. public EnumMap (
  820. Type type, QName qname, KnownTypeCollection knownTypes)
  821. : base (type, qname, knownTypes)
  822. {
  823. bool has_dc = false;
  824. object [] atts = RuntimeType.GetCustomAttributes (
  825. typeof (DataContractAttribute), false);
  826. if (atts.Length != 0)
  827. has_dc = true;
  828. flag_attr = type.GetCustomAttributes (typeof (FlagsAttribute), false).Length > 0;
  829. enum_members = new List<EnumMemberInfo> ();
  830. BindingFlags flags = BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Static;
  831. foreach (FieldInfo fi in RuntimeType.GetFields (flags)) {
  832. string name = fi.Name;
  833. if (has_dc) {
  834. EnumMemberAttribute ema =
  835. GetEnumMemberAttribute (fi);
  836. if (ema == null)
  837. continue;
  838. if (ema.Value != null)
  839. name = ema.Value;
  840. }
  841. enum_members.Add (new EnumMemberInfo (name, fi.GetValue (null)));
  842. }
  843. }
  844. public override bool IsContractAllowedType { get { return false; } }
  845. private EnumMemberAttribute GetEnumMemberAttribute (
  846. MemberInfo mi)
  847. {
  848. object [] atts = mi.GetCustomAttributes (
  849. typeof (EnumMemberAttribute), false);
  850. if (atts.Length == 0)
  851. return null;
  852. return (EnumMemberAttribute) atts [0];
  853. }
  854. public override void Serialize (object graph,
  855. XmlFormatterSerializer serializer)
  856. {
  857. if (flag_attr) {
  858. long val = Convert.ToInt64 (graph);
  859. string s = null;
  860. foreach (EnumMemberInfo emi in enum_members) {
  861. long f = Convert.ToInt64 (emi.Value);
  862. if ((f & val) == f)
  863. s += (s != null ? " " : String.Empty) + emi.XmlName;
  864. }
  865. if (s != null)
  866. serializer.Writer.WriteString (s);
  867. return;
  868. } else {
  869. foreach (EnumMemberInfo emi in enum_members) {
  870. if (Enum.Equals (emi.Value, graph)) {
  871. serializer.Writer.WriteString (emi.XmlName);
  872. return;
  873. }
  874. }
  875. }
  876. throw new SerializationException (String.Format (
  877. "Enum value '{0}' is invalid for type '{1}' and cannot be serialized.", graph, RuntimeType));
  878. }
  879. public override object DeserializeEmptyContent (XmlReader reader, XmlFormatterDeserializer deserializer, string id)
  880. {
  881. if (!flag_attr)
  882. throw new SerializationException (String.Format ("Enum value '' is invalid for type '{0}' and cannot be deserialized.", RuntimeType));
  883. var instance = Enum.ToObject (RuntimeType, 0);
  884. HandleId (id, deserializer, instance);
  885. return instance;
  886. }
  887. public override object DeserializeContent (XmlReader reader, XmlFormatterDeserializer deserializer, string id)
  888. {
  889. string value = reader.NodeType != XmlNodeType.Text ? String.Empty : reader.ReadContentAsString ();
  890. HandleId (id, deserializer, value);
  891. if (value != String.Empty) {
  892. if (flag_attr && value.IndexOf (' ') != -1) {
  893. long flags = 0L;
  894. foreach (string flag in value.Split (' ')) {
  895. foreach (EnumMemberInfo emi in enum_members) {
  896. if (emi.XmlName == flag) {
  897. flags |= Convert.ToInt64 (emi.Value);
  898. break;
  899. }
  900. }
  901. }
  902. return Enum.ToObject (RuntimeType, flags);
  903. }
  904. else {
  905. foreach (EnumMemberInfo emi in enum_members)
  906. if (emi.XmlName == value)
  907. return emi.Value;
  908. }
  909. }
  910. if (!flag_attr)
  911. throw new SerializationException (String.Format ("Enum value '{0}' is invalid for type '{1}' and cannot be deserialized.", value, RuntimeType));
  912. return Enum.ToObject (RuntimeType, 0);
  913. }
  914. }
  915. internal struct EnumMemberInfo
  916. {
  917. public readonly string XmlName;
  918. public readonly object Value;
  919. public EnumMemberInfo (string name, object value)
  920. {
  921. XmlName = name;
  922. Value = value;
  923. }
  924. }
  925. internal class DataMemberInfo //: KeyValuePair<int, MemberInfo>
  926. {
  927. public readonly int Order;
  928. public readonly bool IsRequired;
  929. public readonly string XmlName;
  930. public readonly MemberInfo Member;
  931. public readonly string XmlNamespace;
  932. public readonly string XmlRootNamespace;
  933. public readonly Type MemberType;
  934. public DataMemberInfo (MemberInfo member, DataMemberAttribute dma, string rootNamespce, string ns)
  935. {
  936. if (dma == null)
  937. throw new ArgumentNullException ("dma");
  938. Order = dma.Order;
  939. Member = member;
  940. IsRequired = dma.IsRequired;
  941. XmlName = XmlConvert.EncodeLocalName (dma.Name != null ? dma.Name : member.Name);
  942. XmlNamespace = ns;
  943. XmlRootNamespace = rootNamespce;
  944. if (Member is FieldInfo)
  945. MemberType = ((FieldInfo) Member).FieldType;
  946. else
  947. MemberType = ((PropertyInfo) Member).PropertyType;
  948. }
  949. public class DataMemberInfoComparer : IComparer<DataMemberInfo>
  950. , IComparer // see bug #76361
  951. {
  952. public static readonly DataMemberInfoComparer Instance
  953. = new DataMemberInfoComparer ();
  954. private DataMemberInfoComparer () {}
  955. public int Compare (object o1, object o2)
  956. {
  957. return Compare ((DataMemberInfo) o1,
  958. (DataMemberInfo) o2);
  959. }
  960. public int Compare (DataMemberInfo d1, DataMemberInfo d2)
  961. {
  962. if (d1.Order == d2.Order)
  963. return String.CompareOrdinal (d1.XmlName, d2.XmlName);
  964. return d1.Order - d2.Order;
  965. }
  966. }
  967. }
  968. }
  969. #endif