PageRenderTime 97ms CodeModel.GetById 28ms RepoModel.GetById 1ms app.codeStats 1ms

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

https://bitbucket.org/steenlund/mono-2.6.7-for-amiga
C# | 800 lines | 621 code | 98 blank | 81 comment | 167 complexity | 0f3e0299b57bb3675b51a17e5cec87c5 MD5 | raw file
Possible License(s): LGPL-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0, LGPL-2.1
  1. //
  2. // KnownTypeCollection.cs
  3. //
  4. // Author:
  5. // Atsushi Enomoto <atsushi@ximian.com>
  6. //
  7. // Copyright (C) 2005 Novell, Inc. http://www.novell.com
  8. //
  9. // Permission is hereby granted, free of charge, to any person obtaining
  10. // a copy of this software and associated documentation files (the
  11. // "Software"), to deal in the Software without restriction, including
  12. // without limitation the rights to use, copy, modify, merge, publish,
  13. // distribute, sublicense, and/or sell copies of the Software, and to
  14. // permit persons to whom the Software is furnished to do so, subject to
  15. // the following conditions:
  16. //
  17. // The above copyright notice and this permission notice shall be
  18. // included in all copies or substantial portions of the Software.
  19. //
  20. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  21. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  22. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  23. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  24. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  25. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  26. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  27. //
  28. #if NET_2_0
  29. using System;
  30. using System.Collections;
  31. using System.Collections.Generic;
  32. using System.Collections.ObjectModel;
  33. using System.Linq;
  34. using System.Reflection;
  35. using System.Xml;
  36. using System.Xml.Schema;
  37. using QName = System.Xml.XmlQualifiedName;
  38. using System.Xml.Serialization;
  39. namespace System.Runtime.Serialization
  40. {
  41. /*
  42. XmlFormatter implementation design inference:
  43. type definitions:
  44. - No XML Schema types are directly used. There are some maps from
  45. xs:blahType to ms:blahType where the namespaceURI for prefix "ms" is
  46. "http://schemas.microsoft.com/2003/10/Serialization/" .
  47. serializable types:
  48. - An object being serialized 1) must be of type System.Object, or
  49. 2) must be null, or 3) must have either a [DataContract] attribute
  50. or a [Serializable] attribute to be serializable.
  51. - When the object is either of type System.Object or null, then the
  52. XML type is "anyType".
  53. - When the object is [Serializable], then the runtime-serialization
  54. compatible object graph is written.
  55. - Otherwise the serialization is based on contract attributes.
  56. ([Serializable] takes precedence).
  57. type derivation:
  58. - For type A to be serializable, the base type B of A must be
  59. serializable.
  60. - If a type which is [Serializable] and whose base type has a
  61. [DataContract], then for base type members [DataContract] is taken.
  62. - It is vice versa i.e. if the base type is [Serializable] and the
  63. derived type has a [DataContract], then [Serializable] takes place
  64. for base members.
  65. known type collection:
  66. - It internally manages mapping store keyed by contract QNames.
  67. KnownTypeCollection.Add() checks if the same QName contract already
  68. exists (and raises InvalidOperationException if required).
  69. */
  70. internal static class TypeExtensions
  71. {
  72. public static T GetCustomAttribute<T> (this Type type, bool inherit)
  73. {
  74. var arr = type.GetCustomAttributes (typeof (T), inherit);
  75. return arr != null && arr.Length == 1 ? (T) arr [0] : default (T);
  76. }
  77. }
  78. internal sealed class KnownTypeCollection : Collection<Type>
  79. {
  80. internal const string MSSimpleNamespace =
  81. "http://schemas.microsoft.com/2003/10/Serialization/";
  82. internal const string MSArraysNamespace =
  83. "http://schemas.microsoft.com/2003/10/Serialization/Arrays";
  84. internal const string DefaultClrNamespaceBase =
  85. "http://schemas.datacontract.org/2004/07/";
  86. static QName any_type, bool_type,
  87. byte_type, date_type, decimal_type, double_type,
  88. float_type, string_type,
  89. short_type, int_type, long_type,
  90. ubyte_type, ushort_type, uint_type, ulong_type,
  91. // non-TypeCode
  92. any_uri_type, base64_type, duration_type, qname_type,
  93. // custom in ms nsURI schema
  94. char_type, guid_type,
  95. // not in ms nsURI schema
  96. dbnull_type;
  97. static KnownTypeCollection ()
  98. {
  99. //any_type, bool_type, byte_type, date_type, decimal_type, double_type, float_type, string_type,
  100. // short_type, int_type, long_type, ubyte_type, ushort_type, uint_type, ulong_type,
  101. // any_uri_type, base64_type, duration_type, qname_type,
  102. // char_type, guid_type, dbnull_type;
  103. string s = MSSimpleNamespace;
  104. any_type = new QName ("anyType", s);
  105. any_uri_type = new QName ("anyURI", s);
  106. bool_type = new QName ("boolean", s);
  107. base64_type = new QName ("base64Binary", s);
  108. date_type = new QName ("dateTime", s);
  109. duration_type = new QName ("duration", s);
  110. qname_type = new QName ("QName", s);
  111. decimal_type = new QName ("decimal", s);
  112. double_type = new QName ("double", s);
  113. float_type = new QName ("float", s);
  114. byte_type = new QName ("byte", s);
  115. short_type = new QName ("short", s);
  116. int_type = new QName ("int", s);
  117. long_type = new QName ("long", s);
  118. ubyte_type = new QName ("unsignedByte", s);
  119. ushort_type = new QName ("unsignedShort", s);
  120. uint_type = new QName ("unsignedInt", s);
  121. ulong_type = new QName ("unsignedLong", s);
  122. string_type = new QName ("string", s);
  123. guid_type = new QName ("guid", s);
  124. char_type = new QName ("char", s);
  125. dbnull_type = new QName ("DBNull", MSSimpleNamespace + "System");
  126. }
  127. // FIXME: find out how QName and guid are processed
  128. internal QName GetXmlName (Type type)
  129. {
  130. SerializationMap map = FindUserMap (type);
  131. if (map != null)
  132. return map.XmlName;
  133. return GetPredefinedTypeName (type);
  134. }
  135. internal static QName GetPredefinedTypeName (Type type)
  136. {
  137. QName name = GetPrimitiveTypeName (type);
  138. if (name != QName.Empty)
  139. return name;
  140. if (type == typeof (DBNull))
  141. return dbnull_type;
  142. return QName.Empty;
  143. }
  144. internal static QName GetPrimitiveTypeName (Type type)
  145. {
  146. if (type.IsGenericType && type.GetGenericTypeDefinition () == typeof (Nullable<>))
  147. return GetPrimitiveTypeName (type.GetGenericArguments () [0]);
  148. if (type.IsEnum)
  149. return QName.Empty;
  150. switch (Type.GetTypeCode (type)) {
  151. case TypeCode.Object: // other than System.Object
  152. case TypeCode.DBNull: // it is natively mapped, but not in ms serialization namespace.
  153. case TypeCode.Empty:
  154. default:
  155. if (type == typeof (object))
  156. return any_type;
  157. if (type == typeof (Guid))
  158. return guid_type;
  159. if (type == typeof (TimeSpan))
  160. return duration_type;
  161. if (type == typeof (byte []))
  162. return base64_type;
  163. if (type == typeof (Uri))
  164. return any_uri_type;
  165. return QName.Empty;
  166. case TypeCode.Boolean:
  167. return bool_type;
  168. case TypeCode.Byte:
  169. return ubyte_type;
  170. case TypeCode.Char:
  171. return char_type;
  172. case TypeCode.DateTime:
  173. return date_type;
  174. case TypeCode.Decimal:
  175. return decimal_type;
  176. case TypeCode.Double:
  177. return double_type;
  178. case TypeCode.Int16:
  179. return short_type;
  180. case TypeCode.Int32:
  181. return int_type;
  182. case TypeCode.Int64:
  183. return long_type;
  184. case TypeCode.SByte:
  185. return byte_type;
  186. case TypeCode.Single:
  187. return float_type;
  188. case TypeCode.String:
  189. return string_type;
  190. case TypeCode.UInt16:
  191. return ushort_type;
  192. case TypeCode.UInt32:
  193. return uint_type;
  194. case TypeCode.UInt64:
  195. return ulong_type;
  196. }
  197. }
  198. internal static string PredefinedTypeObjectToString (object obj)
  199. {
  200. Type type = obj.GetType ();
  201. switch (Type.GetTypeCode (type)) {
  202. case TypeCode.Object: // other than System.Object
  203. case TypeCode.Empty:
  204. default:
  205. if (type == typeof (object))
  206. return String.Empty;
  207. if (type == typeof (Guid))
  208. return XmlConvert.ToString ((Guid) obj);
  209. if (type == typeof (TimeSpan))
  210. return XmlConvert.ToString ((TimeSpan) obj);
  211. if (type == typeof (byte []))
  212. return Convert.ToBase64String ((byte []) obj);
  213. if (type == typeof (Uri))
  214. return ((Uri) obj).ToString ();
  215. throw new Exception ("Internal error: missing predefined type serialization for type " + type.FullName);
  216. case TypeCode.DBNull: // predefined, but not primitive
  217. return String.Empty;
  218. case TypeCode.Boolean:
  219. return XmlConvert.ToString ((bool) obj);
  220. case TypeCode.Byte:
  221. return XmlConvert.ToString ((int)((byte) obj));
  222. case TypeCode.Char:
  223. return XmlConvert.ToString ((uint) (char) obj);
  224. case TypeCode.DateTime:
  225. return XmlConvert.ToString ((DateTime) obj, XmlDateTimeSerializationMode.RoundtripKind);
  226. case TypeCode.Decimal:
  227. return XmlConvert.ToString ((decimal) obj);
  228. case TypeCode.Double:
  229. return XmlConvert.ToString ((double) obj);
  230. case TypeCode.Int16:
  231. return XmlConvert.ToString ((short) obj);
  232. case TypeCode.Int32:
  233. return XmlConvert.ToString ((int) obj);
  234. case TypeCode.Int64:
  235. return XmlConvert.ToString ((long) obj);
  236. case TypeCode.SByte:
  237. return XmlConvert.ToString ((sbyte) obj);
  238. case TypeCode.Single:
  239. return XmlConvert.ToString ((float) obj);
  240. case TypeCode.String:
  241. return (string) obj;
  242. case TypeCode.UInt16:
  243. return XmlConvert.ToString ((int) (ushort) obj);
  244. case TypeCode.UInt32:
  245. return XmlConvert.ToString ((uint) obj);
  246. case TypeCode.UInt64:
  247. return XmlConvert.ToString ((ulong) obj);
  248. }
  249. }
  250. // FIXME: xsd types and ms serialization types should be differentiated.
  251. internal static Type GetPrimitiveTypeFromName (string name)
  252. {
  253. switch (name) {
  254. case "anyURI":
  255. return typeof (Uri);
  256. case "boolean":
  257. return typeof (bool);
  258. case "base64Binary":
  259. return typeof (byte []);
  260. case "dateTime":
  261. return typeof (DateTime);
  262. case "duration":
  263. return typeof (TimeSpan);
  264. case "QName":
  265. return typeof (QName);
  266. case "decimal":
  267. return typeof (decimal);
  268. case "double":
  269. return typeof (double);
  270. case "float":
  271. return typeof (float);
  272. case "byte":
  273. return typeof (sbyte);
  274. case "short":
  275. return typeof (short);
  276. case "int":
  277. return typeof (int);
  278. case "long":
  279. return typeof (long);
  280. case "unsignedByte":
  281. return typeof (byte);
  282. case "unsignedShort":
  283. return typeof (ushort);
  284. case "unsignedInt":
  285. return typeof (uint);
  286. case "unsignedLong":
  287. return typeof (ulong);
  288. case "string":
  289. return typeof (string);
  290. case "anyType":
  291. return typeof (object);
  292. case "guid":
  293. return typeof (Guid);
  294. case "char":
  295. return typeof (char);
  296. default:
  297. return null;
  298. }
  299. }
  300. internal static object PredefinedTypeStringToObject (string s,
  301. string name, XmlReader reader)
  302. {
  303. switch (name) {
  304. case "anyURI":
  305. return new Uri(s,UriKind.RelativeOrAbsolute);
  306. case "boolean":
  307. return XmlConvert.ToBoolean (s);
  308. case "base64Binary":
  309. return Convert.FromBase64String (s);
  310. case "dateTime":
  311. return XmlConvert.ToDateTime (s, XmlDateTimeSerializationMode.RoundtripKind);
  312. case "duration":
  313. return XmlConvert.ToTimeSpan (s);
  314. case "QName":
  315. int idx = s.IndexOf (':');
  316. string l = idx < 0 ? s : s.Substring (idx + 1);
  317. return idx < 0 ? new QName (l) :
  318. new QName (l, reader.LookupNamespace (
  319. s.Substring (0, idx)));
  320. case "decimal":
  321. return XmlConvert.ToDecimal (s);
  322. case "double":
  323. return XmlConvert.ToDouble (s);
  324. case "float":
  325. return XmlConvert.ToSingle (s);
  326. case "byte":
  327. return XmlConvert.ToSByte (s);
  328. case "short":
  329. return XmlConvert.ToInt16 (s);
  330. case "int":
  331. return XmlConvert.ToInt32 (s);
  332. case "long":
  333. return XmlConvert.ToInt64 (s);
  334. case "unsignedByte":
  335. return XmlConvert.ToByte (s);
  336. case "unsignedShort":
  337. return XmlConvert.ToUInt16 (s);
  338. case "unsignedInt":
  339. return XmlConvert.ToUInt32 (s);
  340. case "unsignedLong":
  341. return XmlConvert.ToUInt64 (s);
  342. case "string":
  343. return s;
  344. case "guid":
  345. return XmlConvert.ToGuid (s);
  346. case "anyType":
  347. return s;
  348. case "char":
  349. return (char) XmlConvert.ToUInt32 (s);
  350. default:
  351. throw new Exception ("Unanticipated primitive type: " + name);
  352. }
  353. }
  354. List<SerializationMap> contracts = new List<SerializationMap> ();
  355. public KnownTypeCollection ()
  356. {
  357. }
  358. protected override void ClearItems ()
  359. {
  360. base.Clear ();
  361. }
  362. protected override void InsertItem (int index, Type type)
  363. {
  364. if (TryRegister (type))
  365. base.InsertItem (index, type);
  366. }
  367. // FIXME: it could remove other types' dependencies.
  368. protected override void RemoveItem (int index)
  369. {
  370. Type t = base [index];
  371. List<SerializationMap> l = new List<SerializationMap> ();
  372. foreach (SerializationMap m in contracts) {
  373. if (m.RuntimeType == t)
  374. l.Add (m);
  375. }
  376. foreach (SerializationMap m in l) {
  377. contracts.Remove (m);
  378. base.RemoveItem (index);
  379. }
  380. }
  381. protected override void SetItem (int index, Type type)
  382. {
  383. if (index == Count)
  384. InsertItem (index, type);
  385. else {
  386. RemoveItem (index);
  387. if (TryRegister (type))
  388. base.InsertItem (index - 1, type);
  389. }
  390. }
  391. internal SerializationMap FindUserMap (QName qname)
  392. {
  393. for (int i = 0; i < contracts.Count; i++)
  394. if (qname == contracts [i].XmlName)
  395. return contracts [i];
  396. return null;
  397. }
  398. internal Type GetSerializedType (Type type)
  399. {
  400. Type element = GetCollectionElementType (type);
  401. if (element == null)
  402. return type;
  403. QName name = GetQName (type);
  404. var map = FindUserMap (name);
  405. if (map != null)
  406. return map.RuntimeType;
  407. return type;
  408. }
  409. internal SerializationMap FindUserMap (Type type)
  410. {
  411. for (int i = 0; i < contracts.Count; i++)
  412. if (type == contracts [i].RuntimeType)
  413. return contracts [i];
  414. return null;
  415. }
  416. internal QName GetQName (Type type)
  417. {
  418. if (IsPrimitiveNotEnum (type))
  419. return GetPrimitiveTypeName (type);
  420. SerializationMap map = FindUserMap (type);
  421. if (map != null)
  422. // already mapped.
  423. return map.XmlName;
  424. if (type.IsEnum)
  425. return GetEnumQName (type);
  426. QName qname = GetContractQName (type);
  427. if (qname != null)
  428. return qname;
  429. if (type.GetInterface ("System.Xml.Serialization.IXmlSerializable") != null)
  430. //FIXME: Reusing GetSerializableQName here, since we just
  431. //need name of the type..
  432. return GetSerializableQName (type);
  433. qname = GetCollectionContractQName (type);
  434. if (qname != null)
  435. return qname;
  436. Type element = GetCollectionElementType (type);
  437. if (element != null)
  438. return GetCollectionQName (element);
  439. if (GetAttribute<SerializableAttribute> (type) != null)
  440. return GetSerializableQName (type);
  441. // FIXME: it needs in-depth check.
  442. return QName.Empty;
  443. }
  444. QName GetContractQName (Type type)
  445. {
  446. var a = GetAttribute<DataContractAttribute> (type);
  447. return a == null ? null : GetContractQName (type, a.Name, a.Namespace);
  448. }
  449. QName GetCollectionContractQName (Type type)
  450. {
  451. var a = GetAttribute<CollectionDataContractAttribute> (type);
  452. return a == null ? null : GetContractQName (type, a.Name, a.Namespace);
  453. }
  454. internal static QName GetContractQName (Type type, string name, string ns)
  455. {
  456. if (name == null) {
  457. // FIXME: there could be decent ways to get
  458. // the same result...
  459. name = type.Namespace == null || type.Namespace.Length == 0 ? type.Name : type.FullName.Substring (type.Namespace.Length + 1).Replace ('+', '.');
  460. if (type.IsGenericType) {
  461. name = name.Substring (0, name.IndexOf ('`')) + "Of";
  462. foreach (var t in type.GetGenericArguments ())
  463. name += t.Name; // FIXME: check namespaces too
  464. }
  465. }
  466. if (ns == null)
  467. ns = DefaultClrNamespaceBase + type.Namespace;
  468. return new QName (name, ns);
  469. }
  470. private QName GetEnumQName (Type type)
  471. {
  472. string name = null, ns = null;
  473. if (!type.IsEnum)
  474. return null;
  475. var dca = GetAttribute<DataContractAttribute> (type);
  476. if (dca != null) {
  477. ns = dca.Namespace;
  478. name = dca.Name;
  479. }
  480. if (ns == null)
  481. ns = DefaultClrNamespaceBase + type.Namespace;
  482. if (name == null)
  483. name = type.Namespace == null ? type.Name : type.FullName.Substring (type.Namespace.Length + 1).Replace ('+', '.');
  484. return new QName (name, ns);
  485. }
  486. private QName GetCollectionQName (Type element)
  487. {
  488. QName eqname = GetQName (element);
  489. string ns = eqname.Namespace;
  490. if (eqname.Namespace == MSSimpleNamespace)
  491. //Arrays of Primitive types
  492. ns = MSArraysNamespace;
  493. return new QName (
  494. "ArrayOf" + XmlConvert.EncodeLocalName (eqname.Name),
  495. ns);
  496. }
  497. private QName GetSerializableQName (Type type)
  498. {
  499. string xmlName = type.Name;
  500. if (type.IsGenericType) {
  501. xmlName = xmlName.Substring (0, xmlName.IndexOf ('`')) + "Of";
  502. foreach (var t in type.GetGenericArguments ())
  503. xmlName += GetQName (t).Name; // FIXME: check namespaces too
  504. }
  505. string xmlNamespace = DefaultClrNamespaceBase + type.Namespace;
  506. var x = GetAttribute<XmlRootAttribute> (type);
  507. if (x != null) {
  508. xmlName = x.ElementName;
  509. xmlNamespace = x.Namespace;
  510. }
  511. return new QName (XmlConvert.EncodeLocalName (xmlName), xmlNamespace);
  512. }
  513. internal bool IsPrimitiveNotEnum (Type type)
  514. {
  515. if (type.IsEnum)
  516. return false;
  517. if (Type.GetTypeCode (type) != TypeCode.Object) // explicitly primitive
  518. return true;
  519. if (type == typeof (Guid) || type == typeof (object) || type == typeof(TimeSpan) || type == typeof(byte[]) || type==typeof(Uri)) // special primitives
  520. return true;
  521. // nullable
  522. if (type.IsGenericType && type.GetGenericTypeDefinition () == typeof (Nullable<>))
  523. return IsPrimitiveNotEnum (type.GetGenericArguments () [0]);
  524. return false;
  525. }
  526. internal bool TryRegister (Type type)
  527. {
  528. // exclude predefined maps
  529. if (IsPrimitiveNotEnum (type))
  530. return false;
  531. if (FindUserMap (type) != null)
  532. return false;
  533. if (RegisterEnum (type) != null)
  534. return true;
  535. if (RegisterContract (type) != null)
  536. return true;
  537. if (RegisterIXmlSerializable (type) != null)
  538. return true;
  539. if (RegisterDictionary (type) != null)
  540. return true;
  541. if (RegisterCollectionContract (type) != null)
  542. return true;
  543. if (RegisterCollection (type) != null)
  544. return true;
  545. if (GetAttribute<SerializableAttribute> (type) != null) {
  546. RegisterSerializable (type);
  547. return true;
  548. }
  549. RegisterDefaultTypeMap (type);
  550. return true;
  551. }
  552. internal static Type GetCollectionElementType (Type type)
  553. {
  554. if (type.IsArray)
  555. return type.GetElementType ();
  556. Type [] ifaces = type.GetInterfaces ();
  557. foreach (Type i in ifaces)
  558. if (i.IsGenericType && i.GetGenericTypeDefinition ().Equals (typeof (ICollection<>)))
  559. return i.GetGenericArguments () [0];
  560. foreach (Type i in ifaces)
  561. if (i == typeof (IList))
  562. return typeof (object);
  563. return null;
  564. }
  565. internal T GetAttribute<T> (MemberInfo mi) where T : Attribute
  566. {
  567. object [] atts = mi.GetCustomAttributes (typeof (T), false);
  568. return atts.Length == 0 ? null : (T) atts [0];
  569. }
  570. private CollectionContractTypeMap RegisterCollectionContract (Type type)
  571. {
  572. var cdca = GetAttribute<CollectionDataContractAttribute> (type);
  573. if (cdca == null)
  574. return null;
  575. Type element = GetCollectionElementType (type);
  576. if (element == null)
  577. throw new InvalidOperationException (String.Format ("Type '{0}' is marked as collection contract, but it is not a collection", type));
  578. TryRegister (element); // must be registered before the name conflict check.
  579. QName qname = GetCollectionContractQName (type);
  580. CheckStandardQName (qname);
  581. if (FindUserMap (qname) != null)
  582. throw new InvalidOperationException (String.Format ("Failed to add type {0} to known type collection. There already is a registered type for XML name {1}", type, qname));
  583. var ret = new CollectionContractTypeMap (type, cdca, element, qname, this);
  584. contracts.Add (ret);
  585. return ret;
  586. }
  587. private CollectionTypeMap RegisterCollection (Type type)
  588. {
  589. Type element = GetCollectionElementType (type);
  590. if (element == null)
  591. return null;
  592. TryRegister (element);
  593. QName qname = GetCollectionQName (element);
  594. var map = FindUserMap (qname);
  595. if (map != null) {
  596. var cmap = map as CollectionTypeMap;
  597. if (cmap == null || cmap.RuntimeType != type)
  598. throw new InvalidOperationException (String.Format ("Failed to add type {0} to known type collection. There already is a registered type for XML name {1}", type, qname));
  599. return cmap;
  600. }
  601. CollectionTypeMap ret =
  602. new CollectionTypeMap (type, element, qname, this);
  603. contracts.Add (ret);
  604. return ret;
  605. }
  606. static bool TypeImplementsIDictionary (Type type)
  607. {
  608. foreach (var iface in type.GetInterfaces ())
  609. if (iface == typeof (IDictionary) || (iface.IsGenericType && iface.GetGenericTypeDefinition () == typeof (IDictionary<,>)))
  610. return true;
  611. return false;
  612. }
  613. // it also supports contract-based dictionary.
  614. private DictionaryTypeMap RegisterDictionary (Type type)
  615. {
  616. if (!TypeImplementsIDictionary (type))
  617. return null;
  618. var cdca = GetAttribute<CollectionDataContractAttribute> (type);
  619. DictionaryTypeMap ret =
  620. new DictionaryTypeMap (type, cdca, this);
  621. if (FindUserMap (ret.XmlName) != null)
  622. throw new InvalidOperationException (String.Format ("Failed to add type {0} to known type collection. There already is a registered type for XML name {1}", type, ret.XmlName));
  623. contracts.Add (ret);
  624. TryRegister (ret.KeyType);
  625. TryRegister (ret.ValueType);
  626. return ret;
  627. }
  628. private SerializationMap RegisterSerializable (Type type)
  629. {
  630. QName qname = GetSerializableQName (type);
  631. if (FindUserMap (qname) != null)
  632. throw new InvalidOperationException (String.Format ("There is already a registered type for XML name {0}", qname));
  633. SharedTypeMap ret =
  634. new SharedTypeMap (type, qname, this);
  635. contracts.Add (ret);
  636. return ret;
  637. }
  638. private SerializationMap RegisterIXmlSerializable (Type type)
  639. {
  640. if (type.GetInterface ("System.Xml.Serialization.IXmlSerializable") == null)
  641. return null;
  642. QName qname = GetSerializableQName (type);
  643. if (FindUserMap (qname) != null)
  644. throw new InvalidOperationException (String.Format ("There is already a registered type for XML name {0}", qname));
  645. XmlSerializableMap ret = new XmlSerializableMap (type, qname, this);
  646. contracts.Add (ret);
  647. return ret;
  648. }
  649. void CheckStandardQName (QName qname)
  650. {
  651. switch (qname.Namespace) {
  652. case XmlSchema.Namespace:
  653. case XmlSchema.InstanceNamespace:
  654. case MSSimpleNamespace:
  655. case MSArraysNamespace:
  656. throw new InvalidOperationException (String.Format ("Namespace {0} is reserved and cannot be used for user serialization", qname.Namespace));
  657. }
  658. }
  659. private SharedContractMap RegisterContract (Type type)
  660. {
  661. QName qname = GetContractQName (type);
  662. if (qname == null)
  663. return null;
  664. CheckStandardQName (qname);
  665. if (FindUserMap (qname) != null)
  666. throw new InvalidOperationException (String.Format ("There is already a registered type for XML name {0}", qname));
  667. SharedContractMap ret = new SharedContractMap (type, qname, this);
  668. contracts.Add (ret);
  669. ret.Initialize ();
  670. object [] attrs = type.GetCustomAttributes (typeof (KnownTypeAttribute), true);
  671. for (int i = 0; i < attrs.Length; i++) {
  672. KnownTypeAttribute kt = (KnownTypeAttribute) attrs [i];
  673. TryRegister (kt.Type);
  674. }
  675. return ret;
  676. }
  677. DefaultTypeMap RegisterDefaultTypeMap (Type type)
  678. {
  679. DefaultTypeMap ret = new DefaultTypeMap (type, this);
  680. contracts.Add (ret);
  681. return ret;
  682. }
  683. private EnumMap RegisterEnum (Type type)
  684. {
  685. QName qname = GetEnumQName (type);
  686. if (qname == null)
  687. return null;
  688. if (FindUserMap (qname) != null)
  689. throw new InvalidOperationException (String.Format ("There is already a registered type for XML name {0}", qname));
  690. EnumMap ret =
  691. new EnumMap (type, qname, this);
  692. contracts.Add (ret);
  693. return ret;
  694. }
  695. }
  696. }
  697. #endif