2010-06-21 Atsushi Enomoto <atsushi@ximian.com>
[mcs.git] / class / System.Runtime.Serialization / System.Runtime.Serialization / KnownTypeCollection.cs
blobd85a91774efad1ba0e3a6b7cf1b8bc07e491f212
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 internal 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 name = GetDefaultName (type);
504 if (ns == null)
505 ns = GetDefaultNamespace (type);
506 return new QName (name, ns);
509 static QName GetEnumQName (Type type)
511 string name = null, ns = null;
513 if (!type.IsEnum)
514 return null;
516 var dca = GetAttribute<DataContractAttribute> (type);
518 if (dca != null) {
519 ns = dca.Namespace;
520 name = dca.Name;
523 if (ns == null)
524 ns = GetDefaultNamespace (type);
526 if (name == null)
527 name = type.Namespace == null ? type.Name : type.FullName.Substring (type.Namespace.Length + 1).Replace ('+', '.');
529 return new QName (name, ns);
532 internal static string GetDefaultName (Type type)
534 // FIXME: there could be decent ways to get
535 // the same result...
536 string name = type.Namespace == null || type.Namespace.Length == 0 ? type.Name : type.FullName.Substring (type.Namespace.Length + 1).Replace ('+', '.');
537 if (type.IsGenericType) {
538 name = name.Substring (0, name.IndexOf ('`')) + "Of";
539 foreach (var t in type.GetGenericArguments ())
540 name += t.Name; // FIXME: check namespaces too
542 return name;
545 internal static string GetDefaultNamespace (Type type)
547 foreach (ContractNamespaceAttribute a in type.Assembly.GetCustomAttributes (typeof (ContractNamespaceAttribute), true))
548 if (a.ClrNamespace == type.Namespace)
549 return a.ContractNamespace;
550 return DefaultClrNamespaceBase + type.Namespace;
553 static QName GetCollectionQName (Type element)
555 QName eqname = GetStaticQName (element);
557 string ns = eqname.Namespace;
558 if (eqname.Namespace == MSSimpleNamespace)
559 //Arrays of Primitive types
560 ns = MSArraysNamespace;
562 return new QName (
563 "ArrayOf" + XmlConvert.EncodeLocalName (eqname.Name),
564 ns);
567 static QName GetSerializableQName (Type type)
569 string xmlName = type.Name;
570 if (type.IsGenericType) {
571 xmlName = xmlName.Substring (0, xmlName.IndexOf ('`')) + "Of";
572 foreach (var t in type.GetGenericArguments ())
573 xmlName += GetStaticQName (t).Name; // FIXME: check namespaces too
575 string xmlNamespace = GetDefaultNamespace (type);
576 var x = GetAttribute<XmlRootAttribute> (type);
577 if (x != null) {
578 xmlName = x.ElementName;
579 xmlNamespace = x.Namespace;
581 return new QName (XmlConvert.EncodeLocalName (xmlName), xmlNamespace);
584 static bool IsPrimitiveNotEnum (Type type)
586 if (type.IsEnum)
587 return false;
588 if (Type.GetTypeCode (type) != TypeCode.Object) // explicitly primitive
589 return true;
590 if (type == typeof (Guid) || type == typeof (object) || type == typeof(TimeSpan) || type == typeof(byte[]) || type==typeof(Uri)) // special primitives
591 return true;
592 // nullable
593 if (type.IsGenericType && type.GetGenericTypeDefinition () == typeof (Nullable<>))
594 return IsPrimitiveNotEnum (type.GetGenericArguments () [0]);
595 return false;
598 internal bool TryRegister (Type type)
600 // exclude predefined maps
601 if (IsPrimitiveNotEnum (type))
602 return false;
604 if (FindUserMap (type) != null)
605 return false;
607 if (RegisterEnum (type) != null)
608 return true;
610 if (RegisterDictionary (type) != null)
611 return true;
613 if (RegisterCollectionContract (type) != null)
614 return true;
616 if (RegisterContract (type) != null)
617 return true;
619 if (RegisterIXmlSerializable (type) != null)
620 return true;
622 if (RegisterCollection (type) != null)
623 return true;
625 if (GetAttribute<SerializableAttribute> (type) != null) {
626 RegisterSerializable (type);
627 return true;
630 RegisterDefaultTypeMap (type);
631 return true;
634 static Type GetCollectionElementType (Type type)
636 if (type.IsArray)
637 return type.GetElementType ();
639 Type [] ifaces = type.GetInterfaces ();
640 foreach (Type i in ifaces)
641 if (i.IsGenericType && i.GetGenericTypeDefinition ().Equals (typeof (ICollection<>)))
642 return i.GetGenericArguments () [0];
643 foreach (Type i in ifaces)
644 if (i == typeof (IList))
645 return typeof (object);
646 return null;
649 internal static T GetAttribute<T> (ICustomAttributeProvider ap) where T : Attribute
651 object [] atts = ap.GetCustomAttributes (typeof (T), false);
652 return atts.Length == 0 ? null : (T) atts [0];
655 private CollectionContractTypeMap RegisterCollectionContract (Type type)
657 var cdca = GetAttribute<CollectionDataContractAttribute> (type);
658 if (cdca == null)
659 return null;
661 Type element = GetCollectionElementType (type);
662 if (element == null)
663 throw new InvalidOperationException (String.Format ("Type '{0}' is marked as collection contract, but it is not a collection", type));
665 TryRegister (element); // must be registered before the name conflict check.
667 QName qname = GetCollectionContractQName (type);
668 CheckStandardQName (qname);
669 if (FindUserMap (qname) != null)
670 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));
672 var ret = new CollectionContractTypeMap (type, cdca, element, qname, this);
673 contracts.Add (ret);
674 return ret;
677 private CollectionTypeMap RegisterCollection (Type type)
679 Type element = GetCollectionElementType (type);
680 if (element == null)
681 return null;
683 TryRegister (element);
685 QName qname = GetCollectionQName (element);
687 var map = FindUserMap (qname);
688 if (map != null) {
689 var cmap = map as CollectionTypeMap;
690 if (cmap == null || cmap.RuntimeType != type)
691 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));
692 return cmap;
695 CollectionTypeMap ret =
696 new CollectionTypeMap (type, element, qname, this);
697 contracts.Add (ret);
698 return ret;
701 static bool TypeImplementsIDictionary (Type type)
703 foreach (var iface in type.GetInterfaces ())
704 if (iface == typeof (IDictionary) || (iface.IsGenericType && iface.GetGenericTypeDefinition () == typeof (IDictionary<,>)))
705 return true;
707 return false;
710 // it also supports contract-based dictionary.
711 private DictionaryTypeMap RegisterDictionary (Type type)
713 if (!TypeImplementsIDictionary (type))
714 return null;
716 var cdca = GetAttribute<CollectionDataContractAttribute> (type);
718 DictionaryTypeMap ret =
719 new DictionaryTypeMap (type, cdca, this);
721 if (FindUserMap (ret.XmlName) != null)
722 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));
723 contracts.Add (ret);
725 TryRegister (ret.KeyType);
726 TryRegister (ret.ValueType);
728 return ret;
731 private SerializationMap RegisterSerializable (Type type)
733 QName qname = GetSerializableQName (type);
735 if (FindUserMap (qname) != null)
736 throw new InvalidOperationException (String.Format ("There is already a registered type for XML name {0}", qname));
738 SharedTypeMap ret = new SharedTypeMap (type, qname, this);
739 contracts.Add (ret);
740 ret.Initialize ();
741 return ret;
744 private SerializationMap RegisterIXmlSerializable (Type type)
746 if (type.GetInterface ("System.Xml.Serialization.IXmlSerializable") == null)
747 return null;
749 QName qname = GetSerializableQName (type);
751 if (FindUserMap (qname) != null)
752 throw new InvalidOperationException (String.Format ("There is already a registered type for XML name {0}", qname));
754 XmlSerializableMap ret = new XmlSerializableMap (type, qname, this);
755 contracts.Add (ret);
757 return ret;
760 void CheckStandardQName (QName qname)
762 switch (qname.Namespace) {
763 case XmlSchema.Namespace:
764 case XmlSchema.InstanceNamespace:
765 case MSSimpleNamespace:
766 case MSArraysNamespace:
767 throw new InvalidOperationException (String.Format ("Namespace {0} is reserved and cannot be used for user serialization", qname.Namespace));
772 private SharedContractMap RegisterContract (Type type)
774 QName qname = GetContractQName (type);
775 if (qname == null)
776 return null;
777 CheckStandardQName (qname);
778 if (FindUserMap (qname) != null)
779 throw new InvalidOperationException (String.Format ("There is already a registered type for XML name {0}", qname));
781 SharedContractMap ret = new SharedContractMap (type, qname, this);
782 contracts.Add (ret);
783 ret.Initialize ();
785 object [] attrs = type.GetCustomAttributes (typeof (KnownTypeAttribute), true);
786 for (int i = 0; i < attrs.Length; i++) {
787 KnownTypeAttribute kt = (KnownTypeAttribute) attrs [i];
788 TryRegister (kt.Type);
791 return ret;
794 DefaultTypeMap RegisterDefaultTypeMap (Type type)
796 DefaultTypeMap ret = new DefaultTypeMap (type, this);
797 contracts.Add (ret);
798 return ret;
801 private EnumMap RegisterEnum (Type type)
803 QName qname = GetEnumQName (type);
804 if (qname == null)
805 return null;
807 if (FindUserMap (qname) != null)
808 throw new InvalidOperationException (String.Format ("There is already a registered type for XML name {0}", qname));
810 EnumMap ret =
811 new EnumMap (type, qname, this);
812 contracts.Add (ret);
813 return ret;
817 #endif