2 // System.Xml.Serialization.TypeData
5 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
6 // Lluis Sanchez Gual (lluis@ximian.com)
8 // (C) 2002 Ximian, Inc (http://www.ximian.com)
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 using System.Collections;
34 using System.Globalization;
35 using System.Reflection;
36 using System.Xml.Schema;
38 namespace System.Xml.Serialization
40 internal class TypeData
48 TypeData listItemTypeData;
49 TypeData listTypeData;
51 XmlSchemaPatternFacet facet;
52 bool hasPublicConstructor = true;
54 public TypeData (Type type, string elementName, bool isPrimitive) :
55 this(type, elementName, isPrimitive, null, null) {}
57 public TypeData (Type type, string elementName, bool isPrimitive, TypeData mappedType, XmlSchemaPatternFacet facet)
59 this.mappedType = mappedType;
62 this.typeName = type.Name;
63 this.fullTypeName = type.FullName.Replace ('+', '.');
66 sType = SchemaTypes.Primitive;
70 sType = SchemaTypes.Enum;
71 else if (typeof(IXmlSerializable).IsAssignableFrom (type))
72 sType = SchemaTypes.XmlSerializable;
73 else if (typeof (System.Xml.XmlNode).IsAssignableFrom (type))
74 sType = SchemaTypes.XmlNode;
75 else if (type.IsArray || typeof(IEnumerable).IsAssignableFrom (type))
76 sType = SchemaTypes.Array;
78 sType = SchemaTypes.Class;
82 this.elementName = TypeTranslator.GetArrayName (ListItemTypeData.XmlType);
84 this.elementName = elementName;
86 if (sType == SchemaTypes.Array || sType == SchemaTypes.Class) {
87 hasPublicConstructor = !type.IsInterface && (type.IsArray || type.GetConstructor (Type.EmptyTypes) != null || type.IsAbstract || type.IsValueType);
91 internal TypeData (string typeName, string fullTypeName, string xmlType, SchemaTypes schemaType, TypeData listItemTypeData)
93 this.elementName = xmlType;
94 this.typeName = typeName;
95 this.fullTypeName = fullTypeName.Replace ('+', '.');
96 this.listItemTypeData = listItemTypeData;
97 this.sType = schemaType;
98 this.hasPublicConstructor = true;
101 public string TypeName
108 public string XmlType
122 public string FullTypeName
129 public SchemaTypes SchemaType
136 public bool IsListType
138 get { return SchemaType == SchemaTypes.Array; }
141 public bool IsComplexType
145 return (SchemaType == SchemaTypes.Class ||
146 SchemaType == SchemaTypes.Array ||
147 SchemaType == SchemaTypes.Enum ||
148 SchemaType == SchemaTypes.XmlNode ||
149 SchemaType == SchemaTypes.XmlSerializable ||
154 public bool IsValueType
158 if (type != null) return type.IsValueType;
159 else return (sType == SchemaTypes.Primitive || sType == SchemaTypes.Enum);
163 public TypeData ListItemTypeData
167 if (listItemTypeData == null && type != null)
168 listItemTypeData = TypeTranslator.GetTypeData (ListItemType);
169 return listItemTypeData;
173 public Type ListItemType
178 throw new InvalidOperationException ("Property ListItemType is not supported for custom types");
180 if (listItemType != null) return listItemType;
182 if (SchemaType != SchemaTypes.Array)
183 throw new InvalidOperationException (Type.FullName + " is not a collection");
184 else if (type.IsArray)
185 listItemType = type.GetElementType ();
186 else if (typeof(ICollection).IsAssignableFrom (type))
188 if (typeof (IDictionary).IsAssignableFrom (type))
189 throw new NotSupportedException (string.Format (CultureInfo.InvariantCulture,
190 "The type {0} is not supported because it implements" +
191 " IDictionary.", type.FullName));
193 PropertyInfo prop = GetIndexerProperty (type);
195 throw new InvalidOperationException ("You must implement a default accessor on " + type.FullName + " because it inherits from ICollection");
197 listItemType = prop.PropertyType;
199 MethodInfo addMethod = type.GetMethod ("Add", new Type[] { listItemType });
200 if (addMethod == null)
201 throw CreateMissingAddMethodException (type, "ICollection",
204 else // at this point, we must be dealing with IEnumerable implementation
206 MethodInfo met = type.GetMethod ("GetEnumerator", Type.EmptyTypes);
208 // get private implemenation
209 met = type.GetMethod ("System.Collections.IEnumerable.GetEnumerator",
210 BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance,
211 null, Type.EmptyTypes, null);
213 // determine ListItemType using IEnumerator.Current property
214 PropertyInfo prop = met.ReturnType.GetProperty ("Current");
216 listItemType = typeof (object);
218 listItemType = prop.PropertyType;
220 MethodInfo addMethod = type.GetMethod ("Add", new Type[] { listItemType });
221 if (addMethod == null)
222 throw CreateMissingAddMethodException (type, "IEnumerable",
230 public TypeData ListTypeData
234 if (listTypeData != null) return listTypeData;
236 listTypeData = new TypeData (TypeName + "[]",
238 TypeTranslator.GetArrayName(XmlType),
239 SchemaTypes.Array, this);
245 public bool IsXsdType {
246 get { return mappedType == null; }
249 public TypeData MappedType {
251 return mappedType != null ? mappedType : this;
255 public XmlSchemaPatternFacet XmlSchemaPatternFacet {
261 public bool HasPublicConstructor
263 get { return hasPublicConstructor; }
267 public static PropertyInfo GetIndexerProperty (Type collectionType)
269 PropertyInfo[] props = collectionType.GetProperties (BindingFlags.Instance | BindingFlags.Public);
270 foreach (PropertyInfo prop in props)
272 ParameterInfo[] pi = prop.GetIndexParameters ();
273 if (pi != null && pi.Length == 1 && pi[0].ParameterType == typeof(int))
279 private static InvalidOperationException CreateMissingAddMethodException (Type type, string inheritFrom, Type argumentType) {
280 return new InvalidOperationException (string.Format(CultureInfo.InvariantCulture,
281 "To be XML serializable, types which inherit from {0} must have " +
282 "an implementation of Add({1}) at all levels of their inheritance " +
283 "hierarchy. {2} does not implement Add({1}).", inheritFrom,
284 argumentType.FullName, type.FullName));