2 // KnownTypeCollection.cs
5 // Atsushi Enomoto <atsushi@ximian.com>
7 // Copyright (C) 2005 Novell, Inc. http://www.novell.com
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:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
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.
30 using System.Collections;
31 using System.Collections.Generic;
32 using System.Collections.ObjectModel;
34 using System.Reflection;
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:
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/" .
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).
63 - For type A to be serializable, the base type B of A must be
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
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 MemberInfo type, bool inherit)
81 var arr = type.GetCustomAttributes (typeof (T), inherit);
82 return arr != null && arr.Length == 1 ? (T) arr [0] : default (T);
85 public static IEnumerable<Type> GetInterfacesOrSelfInterface (this Type type)
89 foreach (var t in type.GetInterfaces ())
94 internal sealed class KnownTypeCollection : Collection<Type>
96 internal const string MSSimpleNamespace =
97 "http://schemas.microsoft.com/2003/10/Serialization/";
98 internal const string MSArraysNamespace =
99 "http://schemas.microsoft.com/2003/10/Serialization/Arrays";
100 internal const string DefaultClrNamespaceBase =
101 "http://schemas.datacontract.org/2004/07/";
102 internal const string DefaultClrNamespaceSystem =
103 "http://schemas.datacontract.org/2004/07/System";
106 static QName any_type, bool_type,
107 byte_type, date_type, decimal_type, double_type,
108 float_type, string_type,
109 short_type, int_type, long_type,
110 ubyte_type, ushort_type, uint_type, ulong_type,
112 any_uri_type, base64_type, duration_type, qname_type,
113 // custom in ms nsURI schema
114 char_type, guid_type,
115 // not in ms nsURI schema
116 dbnull_type, date_time_offset_type;
118 // XmlSchemaType.GetBuiltInPrimitiveType() does not exist in moonlight, so I had to explicitly add them. And now that we have it, it does not make much sense to use #if MOONLIGHT ... #endif for XmlSchemaType anymore :-(
119 static Dictionary<string,Type> xs_predefined_types = new Dictionary<string,Type> ();
121 static KnownTypeCollection ()
123 string s = MSSimpleNamespace;
124 any_type = new QName ("anyType", s);
125 any_uri_type = new QName ("anyURI", s);
126 bool_type = new QName ("boolean", s);
127 base64_type = new QName ("base64Binary", s);
128 date_type = new QName ("dateTime", s);
129 duration_type = new QName ("duration", s);
130 qname_type = new QName ("QName", s);
131 decimal_type = new QName ("decimal", s);
132 double_type = new QName ("double", s);
133 float_type = new QName ("float", s);
134 byte_type = new QName ("byte", s);
135 short_type = new QName ("short", s);
136 int_type = new QName ("int", s);
137 long_type = new QName ("long", s);
138 ubyte_type = new QName ("unsignedByte", s);
139 ushort_type = new QName ("unsignedShort", s);
140 uint_type = new QName ("unsignedInt", s);
141 ulong_type = new QName ("unsignedLong", s);
142 string_type = new QName ("string", s);
143 guid_type = new QName ("guid", s);
144 char_type = new QName ("char", s);
146 dbnull_type = new QName ("DBNull", DefaultClrNamespaceBase + "System");
147 date_time_offset_type = new QName ("DateTimeOffset", DefaultClrNamespaceBase + "System");
149 xs_predefined_types.Add ("string", typeof (string));
150 xs_predefined_types.Add ("boolean", typeof (bool));
151 xs_predefined_types.Add ("float", typeof (float));
152 xs_predefined_types.Add ("double", typeof (double));
153 xs_predefined_types.Add ("decimal", typeof (decimal));
154 xs_predefined_types.Add ("duration", typeof (TimeSpan));
155 xs_predefined_types.Add ("dateTime", typeof (DateTime));
156 xs_predefined_types.Add ("date", typeof (DateTime));
157 xs_predefined_types.Add ("time", typeof (DateTime));
158 xs_predefined_types.Add ("gYearMonth", typeof (DateTime));
159 xs_predefined_types.Add ("gYear", typeof (DateTime));
160 xs_predefined_types.Add ("gMonthDay", typeof (DateTime));
161 xs_predefined_types.Add ("gDay", typeof (DateTime));
162 xs_predefined_types.Add ("gMonth", typeof (DateTime));
163 xs_predefined_types.Add ("hexBinary", typeof (byte []));
164 xs_predefined_types.Add ("base64Binary", typeof (byte []));
165 xs_predefined_types.Add ("anyURI", typeof (Uri));
166 xs_predefined_types.Add ("QName", typeof (QName));
167 xs_predefined_types.Add ("NOTATION", typeof (string));
169 xs_predefined_types.Add ("normalizedString", typeof (string));
170 xs_predefined_types.Add ("token", typeof (string));
171 xs_predefined_types.Add ("language", typeof (string));
172 xs_predefined_types.Add ("IDREFS", typeof (string []));
173 xs_predefined_types.Add ("ENTITIES", typeof (string []));
174 xs_predefined_types.Add ("NMTOKEN", typeof (string));
175 xs_predefined_types.Add ("NMTOKENS", typeof (string []));
176 xs_predefined_types.Add ("Name", typeof (string));
177 xs_predefined_types.Add ("NCName", typeof (string));
178 xs_predefined_types.Add ("ID", typeof (string));
179 xs_predefined_types.Add ("IDREF", typeof (string));
180 xs_predefined_types.Add ("ENTITY", typeof (string));
182 xs_predefined_types.Add ("integer", typeof (decimal));
183 xs_predefined_types.Add ("nonPositiveInteger", typeof (int));
184 xs_predefined_types.Add ("negativeInteger", typeof (int));
185 xs_predefined_types.Add ("long", typeof (long));
186 xs_predefined_types.Add ("int", typeof (int));
187 xs_predefined_types.Add ("short", typeof (short));
188 xs_predefined_types.Add ("byte", typeof (sbyte));
189 xs_predefined_types.Add ("nonNegativeInteger", typeof (decimal));
190 xs_predefined_types.Add ("unsignedLong", typeof (ulong));
191 xs_predefined_types.Add ("unsignedInt", typeof (uint));
192 xs_predefined_types.Add ("unsignedShort", typeof (ushort));
193 xs_predefined_types.Add ("unsignedByte", typeof (byte));
194 xs_predefined_types.Add ("positiveInteger", typeof (decimal));
196 xs_predefined_types.Add ("anyType", typeof (object));
199 // FIXME: find out how QName and guid are processed
201 internal QName GetXmlName (Type type)
203 SerializationMap map = FindUserMap (type);
206 return GetPredefinedTypeName (type);
209 internal static QName GetPredefinedTypeName (Type type)
211 QName name = GetPrimitiveTypeName (type);
212 if (name != QName.Empty)
214 if (type == typeof (DBNull))
219 internal static QName GetPrimitiveTypeName (Type type)
221 if (type.IsGenericType && type.GetGenericTypeDefinition () == typeof (Nullable<>))
222 return GetPrimitiveTypeName (type.GetGenericArguments () [0]);
227 switch (Type.GetTypeCode (type)) {
228 case TypeCode.Object: // other than System.Object
229 case TypeCode.DBNull: // it is natively mapped, but not in ms serialization namespace.
232 if (type == typeof (object))
234 if (type == typeof (Guid))
236 if (type == typeof (TimeSpan))
237 return duration_type;
238 if (type == typeof (byte []))
240 if (type == typeof (Uri))
242 if (type == typeof (DateTimeOffset))
243 return date_time_offset_type;
245 case TypeCode.Boolean:
251 case TypeCode.DateTime:
253 case TypeCode.Decimal:
255 case TypeCode.Double:
265 case TypeCode.Single:
267 case TypeCode.String:
269 case TypeCode.UInt16:
271 case TypeCode.UInt32:
273 case TypeCode.UInt64:
278 internal static string PredefinedTypeObjectToString (object obj)
280 Type type = obj.GetType ();
281 switch (Type.GetTypeCode (type)) {
282 case TypeCode.Object: // other than System.Object
285 if (type == typeof (object))
287 if (type == typeof (Guid))
288 return XmlConvert.ToString ((Guid) obj);
289 if (type == typeof (TimeSpan))
290 return XmlConvert.ToString ((TimeSpan) obj);
291 if (type == typeof (byte []))
292 return Convert.ToBase64String ((byte []) obj);
293 if (type == typeof (Uri))
294 return ((Uri) obj).ToString ();
295 throw new Exception ("Internal error: missing predefined type serialization for type " + type.FullName);
296 case TypeCode.DBNull: // predefined, but not primitive
298 case TypeCode.Boolean:
299 return XmlConvert.ToString ((bool) obj);
301 return XmlConvert.ToString ((int)((byte) obj));
303 return XmlConvert.ToString ((uint) (char) obj);
304 case TypeCode.DateTime:
305 return XmlConvert.ToString ((DateTime) obj, XmlDateTimeSerializationMode.RoundtripKind);
306 case TypeCode.Decimal:
307 return XmlConvert.ToString ((decimal) obj);
308 case TypeCode.Double:
309 return XmlConvert.ToString ((double) obj);
311 return XmlConvert.ToString ((short) obj);
313 return XmlConvert.ToString ((int) obj);
315 return XmlConvert.ToString ((long) obj);
317 return XmlConvert.ToString ((sbyte) obj);
318 case TypeCode.Single:
319 return XmlConvert.ToString ((float) obj);
320 case TypeCode.String:
322 case TypeCode.UInt16:
323 return XmlConvert.ToString ((int) (ushort) obj);
324 case TypeCode.UInt32:
325 return XmlConvert.ToString ((uint) obj);
326 case TypeCode.UInt64:
327 return XmlConvert.ToString ((ulong) obj);
331 internal static Type GetPrimitiveTypeFromName (QName name)
333 switch (name.Namespace) {
334 case DefaultClrNamespaceSystem:
337 return typeof (DBNull);
338 case "DateTimeOffset":
339 return typeof (DateTimeOffset);
342 case XmlSchema.Namespace:
343 return xs_predefined_types.FirstOrDefault (p => p.Key == name.Name).Value;
344 case MSSimpleNamespace:
349 return typeof (bool);
351 return typeof (byte []);
353 return typeof (DateTime);
355 return typeof (TimeSpan);
357 return typeof (QName);
359 return typeof (decimal);
361 return typeof (double);
363 return typeof (float);
365 return typeof (sbyte);
367 return typeof (short);
371 return typeof (long);
373 return typeof (byte);
374 case "unsignedShort":
375 return typeof (ushort);
377 return typeof (uint);
379 return typeof (ulong);
381 return typeof (string);
383 return typeof (object);
385 return typeof (Guid);
387 return typeof (char);
395 internal static object PredefinedTypeStringToObject (string s,
396 string name, XmlReader reader)
400 return new Uri(s,UriKind.RelativeOrAbsolute);
402 return XmlConvert.ToBoolean (s);
404 return Convert.FromBase64String (s);
406 return XmlConvert.ToDateTime (s, XmlDateTimeSerializationMode.RoundtripKind);
408 return XmlConvert.ToTimeSpan (s);
410 int idx = s.IndexOf (':');
411 string l = idx < 0 ? s : s.Substring (idx + 1);
412 return idx < 0 ? new QName (l) :
413 new QName (l, reader.LookupNamespace (
414 s.Substring (0, idx)));
416 return XmlConvert.ToDecimal (s);
418 return XmlConvert.ToDouble (s);
420 return XmlConvert.ToSingle (s);
422 return XmlConvert.ToSByte (s);
424 return XmlConvert.ToInt16 (s);
426 return XmlConvert.ToInt32 (s);
428 return XmlConvert.ToInt64 (s);
430 return XmlConvert.ToByte (s);
431 case "unsignedShort":
432 return XmlConvert.ToUInt16 (s);
434 return XmlConvert.ToUInt32 (s);
436 return XmlConvert.ToUInt64 (s);
440 return XmlConvert.ToGuid (s);
444 return (char) XmlConvert.ToUInt32 (s);
446 throw new Exception ("Unanticipated primitive type: " + name);
450 List<SerializationMap> contracts = new List<SerializationMap> ();
452 public KnownTypeCollection ()
456 protected override void ClearItems ()
461 protected override void InsertItem (int index, Type type)
463 if (ShouldNotRegister (type))
465 if (!Contains (type)) {
467 base.InsertItem (index, type);
471 // FIXME: it could remove other types' dependencies.
472 protected override void RemoveItem (int index)
475 DoRemoveItem (index);
478 void DoRemoveItem (int index)
480 Type t = base [index];
481 List<SerializationMap> l = new List<SerializationMap> ();
482 foreach (SerializationMap m in contracts) {
483 if (m.RuntimeType == t)
486 foreach (SerializationMap m in l) {
487 contracts.Remove (m);
488 base.RemoveItem (index);
492 protected override void SetItem (int index, Type type)
494 if (ShouldNotRegister (type))
497 // Since this collection is not assured to be ordered, it ignores the whole Set operation if the type already exists.
503 if (TryRegister (type))
504 base.InsertItem (index - 1, type);
507 internal SerializationMap FindUserMap (Type type)
510 for (int i = 0; i < contracts.Count; i++)
511 if (type == contracts [i].RuntimeType)
512 return contracts [i];
517 internal SerializationMap FindUserMap (QName qname)
520 return contracts.FirstOrDefault (c => c.XmlName == qname);
523 internal SerializationMap FindUserMap (QName qname, Type type)
526 return contracts.FirstOrDefault (c => c.XmlName == qname && c.RuntimeType == type);
529 internal Type GetSerializedType (Type type)
531 if (IsPrimitiveNotEnum (type))
533 Type element = GetCollectionElementType (type);
536 QName name = GetQName (type);
537 var map = FindUserMap (name, type);
539 return map.RuntimeType;
543 internal QName GetQName (Type type)
545 SerializationMap map = FindUserMap (type);
549 return GetStaticQName (type);
552 public static QName GetStaticQName (Type type)
554 if (IsPrimitiveNotEnum (type))
555 return GetPrimitiveTypeName (type);
558 return GetEnumQName (type);
560 QName qname = GetContractQName (type);
564 if (type.GetInterface ("System.Xml.Serialization.IXmlSerializable") != null)
565 //FIXME: Reusing GetSerializableQName here, since we just
566 //need name of the type..
567 return GetSerializableQName (type);
569 qname = GetCollectionContractQName (type);
573 Type element = GetCollectionElementType (type);
575 return GetCollectionQName (element);
577 if (GetAttribute<SerializableAttribute> (type) != null)
578 return GetSerializableQName (type);
580 // default type map - still uses GetContractQName().
581 return GetContractQName (type, null, null);
584 internal static QName GetContractQName (Type type)
586 var a = GetAttribute<DataContractAttribute> (type);
587 return a == null ? null : GetContractQName (type, a.Name, a.Namespace);
590 static QName GetCollectionContractQName (Type type)
592 var a = GetAttribute<CollectionDataContractAttribute> (type);
593 return a == null ? null : GetContractQName (type, a.Name, a.Namespace);
596 static QName GetContractQName (Type type, string name, string ns)
599 name = GetDefaultName (type);
600 else if (type.IsGenericType) {
601 var args = type.GetGenericArguments ();
602 for (int i = 0; i < args.Length; i++)
603 name = name.Replace ("{" + i + "}", GetStaticQName (args [i]).Name);
607 ns = GetDefaultNamespace (type);
608 return new QName (name, ns);
611 static QName GetEnumQName (Type type)
613 string name = null, ns = null;
618 var dca = GetAttribute<DataContractAttribute> (type);
626 ns = GetDefaultNamespace (type);
629 name = type.Namespace == null ? type.Name : type.FullName.Substring (type.Namespace.Length + 1).Replace ('+', '.');
631 return new QName (name, ns);
634 internal static string GetDefaultName (Type type)
636 // FIXME: there could be decent ways to get
637 // the same result...
638 string name = type.Namespace == null || type.Namespace.Length == 0 ? type.Name : type.FullName.Substring (type.Namespace.Length + 1).Replace ('+', '.');
639 if (type.IsGenericType) {
640 name = name.Substring (0, name.IndexOf ('`')) + "Of";
641 foreach (var t in type.GetGenericArguments ())
642 name += t.Name; // FIXME: check namespaces too
647 internal static string GetDefaultNamespace (Type type)
649 foreach (ContractNamespaceAttribute a in type.Assembly.GetCustomAttributes (typeof (ContractNamespaceAttribute), true))
650 if (a.ClrNamespace == type.Namespace)
651 return a.ContractNamespace;
652 return DefaultClrNamespaceBase + type.Namespace;
655 static QName GetCollectionQName (Type element)
657 QName eqname = GetStaticQName (element);
659 string ns = eqname.Namespace;
660 if (eqname.Namespace == MSSimpleNamespace)
661 //Arrays of Primitive types
662 ns = MSArraysNamespace;
665 "ArrayOf" + XmlConvert.EncodeLocalName (eqname.Name),
669 static QName GetSerializableQName (Type type)
672 // First, check XmlSchemaProviderAttribute and try GetSchema() to see if it returns a schema in the expected format.
673 var xpa = type.GetCustomAttribute<XmlSchemaProviderAttribute> (true);
675 var mi = type.GetMethod (xpa.MethodName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
678 var xss = new XmlSchemaSet ();
679 return (XmlQualifiedName) mi.Invoke (null, new object [] {xss});
687 string xmlName = type.Name;
688 if (type.IsGenericType) {
689 xmlName = xmlName.Substring (0, xmlName.IndexOf ('`')) + "Of";
690 foreach (var t in type.GetGenericArguments ())
691 xmlName += GetStaticQName (t).Name; // FIXME: check namespaces too
693 string xmlNamespace = GetDefaultNamespace (type);
694 var x = GetAttribute<XmlRootAttribute> (type);
696 xmlName = x.ElementName;
697 xmlNamespace = x.Namespace;
699 return new QName (XmlConvert.EncodeLocalName (xmlName), xmlNamespace);
702 static bool IsPrimitiveNotEnum (Type type)
706 if (Type.GetTypeCode (type) != TypeCode.Object) // explicitly primitive
708 if (type == typeof (Guid) || type == typeof (object) || type == typeof(TimeSpan) || type == typeof(byte[]) || type == typeof(Uri) || type == typeof(DateTimeOffset)) // special primitives
712 if (type == typeof (XmlElement) || type == typeof (XmlNode []))
716 if (type.IsGenericType && type.GetGenericTypeDefinition () == typeof (Nullable<>))
717 return IsPrimitiveNotEnum (type.GetGenericArguments () [0]);
721 bool ShouldNotRegister (Type type)
723 return IsPrimitiveNotEnum (type);
726 internal bool TryRegister (Type type)
729 return DoTryRegister (type);
733 bool DoTryRegister (Type type)
735 // exclude predefined maps
736 if (ShouldNotRegister (type))
739 if (FindUserMap (type) != null)
742 if (RegisterEnum (type) != null)
745 if (RegisterDictionary (type) != null)
748 if (RegisterCollectionContract (type) != null)
751 if (RegisterContract (type) != null)
754 if (RegisterIXmlSerializable (type) != null)
757 if (RegisterCollection (type) != null)
760 if (GetAttribute<SerializableAttribute> (type) != null) {
761 RegisterSerializable (type);
765 RegisterDefaultTypeMap (type);
769 static Type GetCollectionElementType (Type type)
772 return type.GetElementType ();
773 var ifaces = type.GetInterfacesOrSelfInterface ();
774 foreach (Type i in ifaces)
775 if (i.IsGenericType && i.GetGenericTypeDefinition ().Equals (typeof (IEnumerable<>)))
776 return i.GetGenericArguments () [0];
777 foreach (Type i in ifaces)
778 if (i == typeof (IList))
779 return typeof (object);
783 internal static T GetAttribute<T> (ICustomAttributeProvider ap) where T : Attribute
785 object [] atts = ap.GetCustomAttributes (typeof (T), false);
786 return atts.Length == 0 ? null : (T) atts [0];
789 private CollectionContractTypeMap RegisterCollectionContract (Type type)
791 var cdca = GetAttribute<CollectionDataContractAttribute> (type);
795 Type element = GetCollectionElementType (type);
797 throw new InvalidOperationException (String.Format ("Type '{0}' is marked as collection contract, but it is not a collection", type));
799 TryRegister (element); // must be registered before the name conflict check.
801 QName qname = GetCollectionContractQName (type);
802 CheckStandardQName (qname);
803 var map = FindUserMap (qname, type);
805 var cmap = map as CollectionContractTypeMap;
806 if (cmap == null) // The runtime type may still differ (between array and other IList; see bug #670560)
807 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));
810 var ret = new CollectionContractTypeMap (type, cdca, element, qname, this);
815 private CollectionTypeMap RegisterCollection (Type type)
817 Type element = GetCollectionElementType (type);
821 TryRegister (element);
823 QName qname = GetCollectionQName (element);
825 var map = FindUserMap (qname, element);
827 var cmap = map as CollectionTypeMap;
828 if (cmap == null) // The runtime type may still differ (between array and other IList; see bug #670560)
829 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));
833 CollectionTypeMap ret =
834 new CollectionTypeMap (type, element, qname, this);
839 static bool TypeImplementsIDictionary (Type type)
841 foreach (var iface in type.GetInterfacesOrSelfInterface ())
842 if (iface == typeof (IDictionary) || (iface.IsGenericType && iface.GetGenericTypeDefinition () == typeof (IDictionary<,>)))
848 // it also supports contract-based dictionary.
849 private DictionaryTypeMap RegisterDictionary (Type type)
851 if (!TypeImplementsIDictionary (type))
854 var cdca = GetAttribute<CollectionDataContractAttribute> (type);
856 DictionaryTypeMap ret =
857 new DictionaryTypeMap (type, cdca, this);
859 TryRegister (ret.KeyType);
860 TryRegister (ret.ValueType);
862 var map = FindUserMap (ret.XmlName, type);
864 var dmap = map as DictionaryTypeMap;
865 if (dmap == null) // The runtime type may still differ (between array and other IList; see bug #670560)
866 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));
873 private SerializationMap RegisterSerializable (Type type)
875 QName qname = GetSerializableQName (type);
877 if (FindUserMap (qname, type) != null)
878 throw new InvalidOperationException (String.Format ("There is already a registered type for XML name {0}", qname));
880 SharedTypeMap ret = new SharedTypeMap (type, qname, this);
886 private SerializationMap RegisterIXmlSerializable (Type type)
888 if (type.GetInterface ("System.Xml.Serialization.IXmlSerializable") == null)
891 QName qname = GetSerializableQName (type);
893 if (FindUserMap (qname, type) != null)
894 throw new InvalidOperationException (String.Format ("There is already a registered type for XML name {0}", qname));
896 XmlSerializableMap ret = new XmlSerializableMap (type, qname, this);
902 void CheckStandardQName (QName qname)
904 switch (qname.Namespace) {
905 case XmlSchema.Namespace:
906 case XmlSchema.InstanceNamespace:
907 case MSSimpleNamespace:
908 case MSArraysNamespace:
909 throw new InvalidOperationException (String.Format ("Namespace {0} is reserved and cannot be used for user serialization", qname.Namespace));
914 private SharedContractMap RegisterContract (Type type)
916 QName qname = GetContractQName (type);
919 CheckStandardQName (qname);
920 if (FindUserMap (qname, type) != null)
921 throw new InvalidOperationException (String.Format ("There is already a registered type for XML name {0}", qname));
923 SharedContractMap ret = new SharedContractMap (type, qname, this);
927 if (type.BaseType != typeof (object)) {
928 TryRegister (type.BaseType);
929 if (!FindUserMap (type.BaseType).IsContractAllowedType)
930 throw new InvalidDataContractException (String.Format ("To be serializable by data contract, type '{0}' cannot inherit from non-contract and non-Serializable type '{1}'", type, type.BaseType));
933 object [] attrs = type.GetCustomAttributes (typeof (KnownTypeAttribute), true);
934 for (int i = 0; i < attrs.Length; i++) {
935 KnownTypeAttribute kt = (KnownTypeAttribute) attrs [i];
936 foreach (var t in kt.GetTypes (type))
943 DefaultTypeMap RegisterDefaultTypeMap (Type type)
945 DefaultTypeMap ret = new DefaultTypeMap (type, this);
951 private EnumMap RegisterEnum (Type type)
953 QName qname = GetEnumQName (type);
957 if (FindUserMap (qname, type) != null)
958 throw new InvalidOperationException (String.Format ("There is already a registered type for XML name {0}", qname));
961 new EnumMap (type, qname, this);