2010-04-15 Jb Evain <jbevain@novell.com>
[mcs.git] / class / System.Runtime.Serialization / System.Runtime.Serialization / KnownTypeCollection.cs
blob62ace1948be4ee6dd1d749b8232b2f0627d93490
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.
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;
38 using QName = System.Xml.XmlQualifiedName;
39 using System.Xml.Serialization;
41 namespace System.Runtime.Serialization
44 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/" .
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).
62 type derivation:
63 - For type A to be serializable, the base type B of A must be
64 serializable.
65 - If a type which is [Serializable] and whose base type has a
66 [DataContract], then for base type members [DataContract] is taken.
67 - It is vice versa i.e. if the base type is [Serializable] and the
68 derived type has a [DataContract], then [Serializable] takes place
69 for base members.
71 known type collection:
72 - It internally manages mapping store keyed by contract QNames.
73 KnownTypeCollection.Add() checks if the same QName contract already
74 exists (and raises InvalidOperationException if required).
77 internal static class TypeExtensions
79 public static T GetCustomAttribute<T> (this Type type, bool inherit)
81 var arr = type.GetCustomAttributes (typeof (T), inherit);
82 return arr != null && arr.Length == 1 ? (T) arr [0] : default (T);
86 internal sealed class KnownTypeCollection : Collection<Type>
88 internal const string MSSimpleNamespace =
89 "http://schemas.microsoft.com/2003/10/Serialization/";
90 internal const string MSArraysNamespace =
91 "http://schemas.microsoft.com/2003/10/Serialization/Arrays";
92 internal const string DefaultClrNamespaceBase =
93 "http://schemas.datacontract.org/2004/07/";
95 static QName any_type, bool_type,
96 byte_type, date_type, decimal_type, double_type,
97 float_type, string_type,
98 short_type, int_type, long_type,
99 ubyte_type, ushort_type, uint_type, ulong_type,
100 // non-TypeCode
101 any_uri_type, base64_type, duration_type, qname_type,
102 // custom in ms nsURI schema
103 char_type, guid_type,
104 // not in ms nsURI schema
105 dbnull_type;
107 static KnownTypeCollection ()
109 //any_type, bool_type, byte_type, date_type, decimal_type, double_type, float_type, string_type,
110 // short_type, int_type, long_type, ubyte_type, ushort_type, uint_type, ulong_type,
111 // any_uri_type, base64_type, duration_type, qname_type,
112 // char_type, guid_type, dbnull_type;
113 string s = MSSimpleNamespace;
114 any_type = new QName ("anyType", s);
115 any_uri_type = new QName ("anyURI", s);
116 bool_type = new QName ("boolean", s);
117 base64_type = new QName ("base64Binary", s);
118 date_type = new QName ("dateTime", s);
119 duration_type = new QName ("duration", s);
120 qname_type = new QName ("QName", s);
121 decimal_type = new QName ("decimal", s);
122 double_type = new QName ("double", s);
123 float_type = new QName ("float", s);
124 byte_type = new QName ("byte", s);
125 short_type = new QName ("short", s);
126 int_type = new QName ("int", s);
127 long_type = new QName ("long", s);
128 ubyte_type = new QName ("unsignedByte", s);
129 ushort_type = new QName ("unsignedShort", s);
130 uint_type = new QName ("unsignedInt", s);
131 ulong_type = new QName ("unsignedLong", s);
132 string_type = new QName ("string", s);
133 guid_type = new QName ("guid", s);
134 char_type = new QName ("char", s);
136 dbnull_type = new QName ("DBNull", MSSimpleNamespace + "System");
139 // FIXME: find out how QName and guid are processed
141 internal QName GetXmlName (Type type)
143 SerializationMap map = FindUserMap (type);
144 if (map != null)
145 return map.XmlName;
146 return GetPredefinedTypeName (type);
149 internal static QName GetPredefinedTypeName (Type type)
151 QName name = GetPrimitiveTypeName (type);
152 if (name != QName.Empty)
153 return name;
154 if (type == typeof (DBNull))
155 return dbnull_type;
156 return QName.Empty;
159 internal static QName GetPrimitiveTypeName (Type type)
161 if (type.IsGenericType && type.GetGenericTypeDefinition () == typeof (Nullable<>))
162 return GetPrimitiveTypeName (type.GetGenericArguments () [0]);
164 if (type.IsEnum)
165 return QName.Empty;
167 switch (Type.GetTypeCode (type)) {
168 case TypeCode.Object: // other than System.Object
169 case TypeCode.DBNull: // it is natively mapped, but not in ms serialization namespace.
170 case TypeCode.Empty:
171 default:
172 if (type == typeof (object))
173 return any_type;
174 if (type == typeof (Guid))
175 return guid_type;
176 if (type == typeof (TimeSpan))
177 return duration_type;
178 if (type == typeof (byte []))
179 return base64_type;
180 if (type == typeof (Uri))
181 return any_uri_type;
182 return QName.Empty;
183 case TypeCode.Boolean:
184 return bool_type;
185 case TypeCode.Byte:
186 return ubyte_type;
187 case TypeCode.Char:
188 return char_type;
189 case TypeCode.DateTime:
190 return date_type;
191 case TypeCode.Decimal:
192 return decimal_type;
193 case TypeCode.Double:
194 return double_type;
195 case TypeCode.Int16:
196 return short_type;
197 case TypeCode.Int32:
198 return int_type;
199 case TypeCode.Int64:
200 return long_type;
201 case TypeCode.SByte:
202 return byte_type;
203 case TypeCode.Single:
204 return float_type;
205 case TypeCode.String:
206 return string_type;
207 case TypeCode.UInt16:
208 return ushort_type;
209 case TypeCode.UInt32:
210 return uint_type;
211 case TypeCode.UInt64:
212 return ulong_type;
216 internal static string PredefinedTypeObjectToString (object obj)
218 Type type = obj.GetType ();
219 switch (Type.GetTypeCode (type)) {
220 case TypeCode.Object: // other than System.Object
221 case TypeCode.Empty:
222 default:
223 if (type == typeof (object))
224 return String.Empty;
225 if (type == typeof (Guid))
226 return XmlConvert.ToString ((Guid) obj);
227 if (type == typeof (TimeSpan))
228 return XmlConvert.ToString ((TimeSpan) obj);
229 if (type == typeof (byte []))
230 return Convert.ToBase64String ((byte []) obj);
231 if (type == typeof (Uri))
232 return ((Uri) obj).ToString ();
233 throw new Exception ("Internal error: missing predefined type serialization for type " + type.FullName);
234 case TypeCode.DBNull: // predefined, but not primitive
235 return String.Empty;
236 case TypeCode.Boolean:
237 return XmlConvert.ToString ((bool) obj);
238 case TypeCode.Byte:
239 return XmlConvert.ToString ((int)((byte) obj));
240 case TypeCode.Char:
241 return XmlConvert.ToString ((uint) (char) obj);
242 case TypeCode.DateTime:
243 return XmlConvert.ToString ((DateTime) obj, XmlDateTimeSerializationMode.RoundtripKind);
244 case TypeCode.Decimal:
245 return XmlConvert.ToString ((decimal) obj);
246 case TypeCode.Double:
247 return XmlConvert.ToString ((double) obj);
248 case TypeCode.Int16:
249 return XmlConvert.ToString ((short) obj);
250 case TypeCode.Int32:
251 return XmlConvert.ToString ((int) obj);
252 case TypeCode.Int64:
253 return XmlConvert.ToString ((long) obj);
254 case TypeCode.SByte:
255 return XmlConvert.ToString ((sbyte) obj);
256 case TypeCode.Single:
257 return XmlConvert.ToString ((float) obj);
258 case TypeCode.String:
259 return (string) obj;
260 case TypeCode.UInt16:
261 return XmlConvert.ToString ((int) (ushort) obj);
262 case TypeCode.UInt32:
263 return XmlConvert.ToString ((uint) obj);
264 case TypeCode.UInt64:
265 return XmlConvert.ToString ((ulong) obj);
269 // FIXME: xsd types and ms serialization types should be differentiated.
270 internal static Type GetPrimitiveTypeFromName (string name)
272 switch (name) {
273 case "anyURI":
274 return typeof (Uri);
275 case "boolean":
276 return typeof (bool);
277 case "base64Binary":
278 return typeof (byte []);
279 case "dateTime":
280 return typeof (DateTime);
281 case "duration":
282 return typeof (TimeSpan);
283 case "QName":
284 return typeof (QName);
285 case "decimal":
286 return typeof (decimal);
287 case "double":
288 return typeof (double);
289 case "float":
290 return typeof (float);
291 case "byte":
292 return typeof (sbyte);
293 case "short":
294 return typeof (short);
295 case "int":
296 return typeof (int);
297 case "long":
298 return typeof (long);
299 case "unsignedByte":
300 return typeof (byte);
301 case "unsignedShort":
302 return typeof (ushort);
303 case "unsignedInt":
304 return typeof (uint);
305 case "unsignedLong":
306 return typeof (ulong);
307 case "string":
308 return typeof (string);
309 case "anyType":
310 return typeof (object);
311 case "guid":
312 return typeof (Guid);
313 case "char":
314 return typeof (char);
315 default:
316 return null;
321 internal static object PredefinedTypeStringToObject (string s,
322 string name, XmlReader reader)
324 switch (name) {
325 case "anyURI":
326 return new Uri(s,UriKind.RelativeOrAbsolute);
327 case "boolean":
328 return XmlConvert.ToBoolean (s);
329 case "base64Binary":
330 return Convert.FromBase64String (s);
331 case "dateTime":
332 return XmlConvert.ToDateTime (s, XmlDateTimeSerializationMode.RoundtripKind);
333 case "duration":
334 return XmlConvert.ToTimeSpan (s);
335 case "QName":
336 int idx = s.IndexOf (':');
337 string l = idx < 0 ? s : s.Substring (idx + 1);
338 return idx < 0 ? new QName (l) :
339 new QName (l, reader.LookupNamespace (
340 s.Substring (0, idx)));
341 case "decimal":
342 return XmlConvert.ToDecimal (s);
343 case "double":
344 return XmlConvert.ToDouble (s);
345 case "float":
346 return XmlConvert.ToSingle (s);
347 case "byte":
348 return XmlConvert.ToSByte (s);
349 case "short":
350 return XmlConvert.ToInt16 (s);
351 case "int":
352 return XmlConvert.ToInt32 (s);
353 case "long":
354 return XmlConvert.ToInt64 (s);
355 case "unsignedByte":
356 return XmlConvert.ToByte (s);
357 case "unsignedShort":
358 return XmlConvert.ToUInt16 (s);
359 case "unsignedInt":
360 return XmlConvert.ToUInt32 (s);
361 case "unsignedLong":
362 return XmlConvert.ToUInt64 (s);
363 case "string":
364 return s;
365 case "guid":
366 return XmlConvert.ToGuid (s);
367 case "anyType":
368 return s;
369 case "char":
370 return (char) XmlConvert.ToUInt32 (s);
371 default:
372 throw new Exception ("Unanticipated primitive type: " + name);
376 List<SerializationMap> contracts = new List<SerializationMap> ();
378 public KnownTypeCollection ()
382 protected override void ClearItems ()
384 base.Clear ();
387 protected override void InsertItem (int index, Type type)
389 if (TryRegister (type))
390 base.InsertItem (index, type);
393 // FIXME: it could remove other types' dependencies.
394 protected override void RemoveItem (int index)
396 Type t = base [index];
397 List<SerializationMap> l = new List<SerializationMap> ();
398 foreach (SerializationMap m in contracts) {
399 if (m.RuntimeType == t)
400 l.Add (m);
402 foreach (SerializationMap m in l) {
403 contracts.Remove (m);
404 base.RemoveItem (index);
408 protected override void SetItem (int index, Type type)
410 if (index == Count)
411 InsertItem (index, type);
412 else {
413 RemoveItem (index);
414 if (TryRegister (type))
415 base.InsertItem (index - 1, type);
419 internal SerializationMap FindUserMap (QName qname)
421 for (int i = 0; i < contracts.Count; i++)
422 if (qname == contracts [i].XmlName)
423 return contracts [i];
424 return null;
427 internal Type GetSerializedType (Type type)
429 Type element = GetCollectionElementType (type);
430 if (element == null)
431 return type;
432 QName name = GetQName (type);
433 var map = FindUserMap (name);
434 if (map != null)
435 return map.RuntimeType;
436 return type;
439 internal SerializationMap FindUserMap (Type type)
441 for (int i = 0; i < contracts.Count; i++)
442 if (type == contracts [i].RuntimeType)
443 return contracts [i];
444 return null;
447 internal QName GetQName (Type type)
449 SerializationMap map = FindUserMap (type);
450 if (map != null)
451 // already mapped.
452 return map.XmlName;
453 return GetStaticQName (type);
456 public static QName GetStaticQName (Type type)
458 if (IsPrimitiveNotEnum (type))
459 return GetPrimitiveTypeName (type);
461 if (type.IsEnum)
462 return GetEnumQName (type);
464 QName qname = GetContractQName (type);
465 if (qname != null)
466 return qname;
468 if (type.GetInterface ("System.Xml.Serialization.IXmlSerializable") != null)
469 //FIXME: Reusing GetSerializableQName here, since we just
470 //need name of the type..
471 return GetSerializableQName (type);
473 qname = GetCollectionContractQName (type);
474 if (qname != null)
475 return qname;
477 Type element = GetCollectionElementType (type);
478 if (element != null)
479 return GetCollectionQName (element);
481 if (GetAttribute<SerializableAttribute> (type) != null)
482 return GetSerializableQName (type);
484 // default type map - still uses GetContractQName().
485 return GetContractQName (type, null, null);
488 static QName GetContractQName (Type type)
490 var a = GetAttribute<DataContractAttribute> (type);
491 return a == null ? null : GetContractQName (type, a.Name, a.Namespace);
494 static QName GetCollectionContractQName (Type type)
496 var a = GetAttribute<CollectionDataContractAttribute> (type);
497 return a == null ? null : GetContractQName (type, a.Name, a.Namespace);
500 static QName GetContractQName (Type type, string name, string ns)
502 if (name == null) {
503 // FIXME: there could be decent ways to get
504 // the same result...
505 name = type.Namespace == null || type.Namespace.Length == 0 ? type.Name : type.FullName.Substring (type.Namespace.Length + 1).Replace ('+', '.');
506 if (type.IsGenericType) {
507 name = name.Substring (0, name.IndexOf ('`')) + "Of";
508 foreach (var t in type.GetGenericArguments ())
509 name += t.Name; // FIXME: check namespaces too
512 if (ns == null)
513 ns = DefaultClrNamespaceBase + type.Namespace;
514 return new QName (name, ns);
517 static QName GetEnumQName (Type type)
519 string name = null, ns = null;
521 if (!type.IsEnum)
522 return null;
524 var dca = GetAttribute<DataContractAttribute> (type);
526 if (dca != null) {
527 ns = dca.Namespace;
528 name = dca.Name;
531 if (ns == null)
532 ns = DefaultClrNamespaceBase + type.Namespace;
534 if (name == null)
535 name = type.Namespace == null ? type.Name : type.FullName.Substring (type.Namespace.Length + 1).Replace ('+', '.');
537 return new QName (name, ns);
540 static QName GetCollectionQName (Type element)
542 QName eqname = GetStaticQName (element);
544 string ns = eqname.Namespace;
545 if (eqname.Namespace == MSSimpleNamespace)
546 //Arrays of Primitive types
547 ns = MSArraysNamespace;
549 return new QName (
550 "ArrayOf" + XmlConvert.EncodeLocalName (eqname.Name),
551 ns);
554 static QName GetSerializableQName (Type type)
556 string xmlName = type.Name;
557 if (type.IsGenericType) {
558 xmlName = xmlName.Substring (0, xmlName.IndexOf ('`')) + "Of";
559 foreach (var t in type.GetGenericArguments ())
560 xmlName += GetStaticQName (t).Name; // FIXME: check namespaces too
562 string xmlNamespace = DefaultClrNamespaceBase + type.Namespace;
563 var x = GetAttribute<XmlRootAttribute> (type);
564 if (x != null) {
565 xmlName = x.ElementName;
566 xmlNamespace = x.Namespace;
568 return new QName (XmlConvert.EncodeLocalName (xmlName), xmlNamespace);
571 static bool IsPrimitiveNotEnum (Type type)
573 if (type.IsEnum)
574 return false;
575 if (Type.GetTypeCode (type) != TypeCode.Object) // explicitly primitive
576 return true;
577 if (type == typeof (Guid) || type == typeof (object) || type == typeof(TimeSpan) || type == typeof(byte[]) || type==typeof(Uri)) // special primitives
578 return true;
579 // nullable
580 if (type.IsGenericType && type.GetGenericTypeDefinition () == typeof (Nullable<>))
581 return IsPrimitiveNotEnum (type.GetGenericArguments () [0]);
582 return false;
585 internal bool TryRegister (Type type)
587 // exclude predefined maps
588 if (IsPrimitiveNotEnum (type))
589 return false;
591 if (FindUserMap (type) != null)
592 return false;
594 if (RegisterEnum (type) != null)
595 return true;
597 if (RegisterContract (type) != null)
598 return true;
600 if (RegisterIXmlSerializable (type) != null)
601 return true;
603 if (RegisterDictionary (type) != null)
604 return true;
606 if (RegisterCollectionContract (type) != null)
607 return true;
609 if (RegisterCollection (type) != null)
610 return true;
612 if (GetAttribute<SerializableAttribute> (type) != null) {
613 RegisterSerializable (type);
614 return true;
617 RegisterDefaultTypeMap (type);
618 return true;
621 static Type GetCollectionElementType (Type type)
623 if (type.IsArray)
624 return type.GetElementType ();
626 Type [] ifaces = type.GetInterfaces ();
627 foreach (Type i in ifaces)
628 if (i.IsGenericType && i.GetGenericTypeDefinition ().Equals (typeof (ICollection<>)))
629 return i.GetGenericArguments () [0];
630 foreach (Type i in ifaces)
631 if (i == typeof (IList))
632 return typeof (object);
633 return null;
636 internal static T GetAttribute<T> (MemberInfo mi) where T : Attribute
638 object [] atts = mi.GetCustomAttributes (typeof (T), false);
639 return atts.Length == 0 ? null : (T) atts [0];
642 private CollectionContractTypeMap RegisterCollectionContract (Type type)
644 var cdca = GetAttribute<CollectionDataContractAttribute> (type);
645 if (cdca == null)
646 return null;
648 Type element = GetCollectionElementType (type);
649 if (element == null)
650 throw new InvalidOperationException (String.Format ("Type '{0}' is marked as collection contract, but it is not a collection", type));
652 TryRegister (element); // must be registered before the name conflict check.
654 QName qname = GetCollectionContractQName (type);
655 CheckStandardQName (qname);
656 if (FindUserMap (qname) != null)
657 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));
659 var ret = new CollectionContractTypeMap (type, cdca, element, qname, this);
660 contracts.Add (ret);
661 return ret;
664 private CollectionTypeMap RegisterCollection (Type type)
666 Type element = GetCollectionElementType (type);
667 if (element == null)
668 return null;
670 TryRegister (element);
672 QName qname = GetCollectionQName (element);
674 var map = FindUserMap (qname);
675 if (map != null) {
676 var cmap = map as CollectionTypeMap;
677 if (cmap == null || cmap.RuntimeType != type)
678 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));
679 return cmap;
682 CollectionTypeMap ret =
683 new CollectionTypeMap (type, element, qname, this);
684 contracts.Add (ret);
685 return ret;
688 static bool TypeImplementsIDictionary (Type type)
690 foreach (var iface in type.GetInterfaces ())
691 if (iface == typeof (IDictionary) || (iface.IsGenericType && iface.GetGenericTypeDefinition () == typeof (IDictionary<,>)))
692 return true;
694 return false;
697 // it also supports contract-based dictionary.
698 private DictionaryTypeMap RegisterDictionary (Type type)
700 if (!TypeImplementsIDictionary (type))
701 return null;
703 var cdca = GetAttribute<CollectionDataContractAttribute> (type);
705 DictionaryTypeMap ret =
706 new DictionaryTypeMap (type, cdca, this);
708 if (FindUserMap (ret.XmlName) != null)
709 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));
710 contracts.Add (ret);
712 TryRegister (ret.KeyType);
713 TryRegister (ret.ValueType);
715 return ret;
718 private SerializationMap RegisterSerializable (Type type)
720 QName qname = GetSerializableQName (type);
722 if (FindUserMap (qname) != null)
723 throw new InvalidOperationException (String.Format ("There is already a registered type for XML name {0}", qname));
725 SharedTypeMap ret = new SharedTypeMap (type, qname, this);
726 contracts.Add (ret);
727 ret.Initialize ();
728 return ret;
731 private SerializationMap RegisterIXmlSerializable (Type type)
733 if (type.GetInterface ("System.Xml.Serialization.IXmlSerializable") == null)
734 return null;
736 QName qname = GetSerializableQName (type);
738 if (FindUserMap (qname) != null)
739 throw new InvalidOperationException (String.Format ("There is already a registered type for XML name {0}", qname));
741 XmlSerializableMap ret = new XmlSerializableMap (type, qname, this);
742 contracts.Add (ret);
744 return ret;
747 void CheckStandardQName (QName qname)
749 switch (qname.Namespace) {
750 case XmlSchema.Namespace:
751 case XmlSchema.InstanceNamespace:
752 case MSSimpleNamespace:
753 case MSArraysNamespace:
754 throw new InvalidOperationException (String.Format ("Namespace {0} is reserved and cannot be used for user serialization", qname.Namespace));
759 private SharedContractMap RegisterContract (Type type)
761 QName qname = GetContractQName (type);
762 if (qname == null)
763 return null;
764 CheckStandardQName (qname);
765 if (FindUserMap (qname) != null)
766 throw new InvalidOperationException (String.Format ("There is already a registered type for XML name {0}", qname));
768 SharedContractMap ret = new SharedContractMap (type, qname, this);
769 contracts.Add (ret);
770 ret.Initialize ();
772 object [] attrs = type.GetCustomAttributes (typeof (KnownTypeAttribute), true);
773 for (int i = 0; i < attrs.Length; i++) {
774 KnownTypeAttribute kt = (KnownTypeAttribute) attrs [i];
775 TryRegister (kt.Type);
778 return ret;
781 DefaultTypeMap RegisterDefaultTypeMap (Type type)
783 DefaultTypeMap ret = new DefaultTypeMap (type, this);
784 contracts.Add (ret);
785 return ret;
788 private EnumMap RegisterEnum (Type type)
790 QName qname = GetEnumQName (type);
791 if (qname == null)
792 return null;
794 if (FindUserMap (qname) != null)
795 throw new InvalidOperationException (String.Format ("There is already a registered type for XML name {0}", qname));
797 EnumMap ret =
798 new EnumMap (type, qname, this);
799 contracts.Add (ret);
800 return ret;
804 #endif