2 // System.Xml.Serialization.TypeData
5 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
6 // Lluis Sanchez Gual (lluis@ximian.com)
7 // Atsushi Enomoto (atsushi@ximian.com)
9 // (C) 2002 Ximian, Inc (http://www.ximian.com)
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 using System.Collections;
35 using System.Globalization;
36 using System.Reflection;
38 using System.Xml.Schema;
40 namespace System.Xml.Serialization
42 internal class TypeData
51 string csharpFullName;
52 TypeData listItemTypeData;
53 TypeData listTypeData;
55 XmlSchemaPatternFacet facet;
56 bool hasPublicConstructor = true;
57 bool nullableOverride;
59 public TypeData (Type type, string elementName, bool isPrimitive) :
60 this(type, elementName, isPrimitive, null, null) {}
62 public TypeData (Type type, string elementName, bool isPrimitive, TypeData mappedType, XmlSchemaPatternFacet facet)
65 if (type.IsGenericTypeDefinition)
66 throw new InvalidOperationException ("Generic type definition cannot be used in serialization. Only specific generic types can be used.");
68 this.mappedType = mappedType;
71 this.typeName = type.Name;
72 this.fullTypeName = type.FullName.Replace ('+', '.');
75 sType = SchemaTypes.Primitive;
79 sType = SchemaTypes.Enum;
80 else if (typeof(IXmlSerializable).IsAssignableFrom (type))
81 sType = SchemaTypes.XmlSerializable;
82 else if (typeof (System.Xml.XmlNode).IsAssignableFrom (type))
83 sType = SchemaTypes.XmlNode;
84 else if (type.IsArray || typeof(IEnumerable).IsAssignableFrom (type))
85 sType = SchemaTypes.Array;
87 sType = SchemaTypes.Class;
91 this.elementName = TypeTranslator.GetArrayName (ListItemTypeData.XmlType);
93 this.elementName = elementName;
95 if (sType == SchemaTypes.Array || sType == SchemaTypes.Class) {
96 hasPublicConstructor = !type.IsInterface && (type.IsArray || type.GetConstructor (Type.EmptyTypes) != null || type.IsAbstract || type.IsValueType);
100 internal TypeData (string typeName, string fullTypeName, string xmlType, SchemaTypes schemaType, TypeData listItemTypeData)
102 this.elementName = xmlType;
103 this.typeName = typeName;
104 this.fullTypeName = fullTypeName.Replace ('+', '.');
105 this.listItemTypeData = listItemTypeData;
106 this.sType = schemaType;
107 this.hasPublicConstructor = true;
110 public string TypeName
117 public string XmlType
131 public string FullTypeName
138 public string CSharpName
141 if (csharpName == null)
142 csharpName = (Type == null) ? TypeName : ToCSharpName (Type, false);
147 public string CSharpFullName
150 if (csharpFullName == null)
151 csharpFullName = (Type == null) ? TypeName : ToCSharpName (Type, true);
152 return csharpFullName;
156 // static Microsoft.CSharp.CSharpCodeProvider csprovider =
157 // new Microsoft.CSharp.CSharpCodeProvider ();
159 public static string ToCSharpName (Type type, bool full)
161 // return csprovider.GetTypeOutput (new System.CodeDom.CodeTypeReference (type));
163 StringBuilder sb = new StringBuilder ();
164 sb.Append (ToCSharpName (type.GetElementType (), full));
166 int rank = type.GetArrayRank ();
167 for (int i = 1; i < rank; i++)
170 return sb.ToString ();
173 if (type.IsGenericType && !type.IsGenericTypeDefinition) {
174 StringBuilder sb = new StringBuilder ();
175 sb.Append (ToCSharpName (type.GetGenericTypeDefinition (), full));
177 foreach (Type arg in type.GetGenericArguments ())
178 sb.Append (ToCSharpName (arg, full)).Append (',');
181 return sb.ToString ();
184 string name = full ? type.FullName : type.Name;
185 name = name.Replace ('+', '.');
186 int idx = name.IndexOf ('`'); // generic definition has extra `n.
187 return idx > 0 ? name.Substring (0, idx) : name;
190 public SchemaTypes SchemaType
197 public bool IsListType
199 get { return SchemaType == SchemaTypes.Array; }
202 public bool IsComplexType
206 return (SchemaType == SchemaTypes.Class ||
207 SchemaType == SchemaTypes.Array ||
208 SchemaType == SchemaTypes.Enum ||
209 SchemaType == SchemaTypes.XmlNode ||
210 SchemaType == SchemaTypes.XmlSerializable ||
215 public bool IsValueType
219 if (type != null) return type.IsValueType;
220 else return (sType == SchemaTypes.Primitive || sType == SchemaTypes.Enum);
224 public bool IsNullable
228 if (nullableOverride)
231 return !IsValueType ||
233 type.IsGenericType &&
234 type.GetGenericTypeDefinition () == typeof (Nullable<>));
242 nullableOverride = true;
246 public TypeData ListItemTypeData
250 if (listItemTypeData == null && type != null)
251 listItemTypeData = TypeTranslator.GetTypeData (ListItemType);
252 return listItemTypeData;
256 public Type ListItemType
261 throw new InvalidOperationException ("Property ListItemType is not supported for custom types");
263 if (listItemType != null) return listItemType;
265 if (SchemaType != SchemaTypes.Array)
266 throw new InvalidOperationException (Type.FullName + " is not a collection");
267 else if (type.IsArray)
268 listItemType = type.GetElementType ();
269 else if (typeof(ICollection).IsAssignableFrom (type))
271 if (typeof (IDictionary).IsAssignableFrom (type))
272 throw new NotSupportedException (string.Format (CultureInfo.InvariantCulture,
273 "The type {0} is not supported because it implements" +
274 " IDictionary.", type.FullName));
276 PropertyInfo prop = GetIndexerProperty (type);
278 throw new InvalidOperationException ("You must implement a default accessor on " + type.FullName + " because it inherits from ICollection");
280 listItemType = prop.PropertyType;
282 MethodInfo addMethod = type.GetMethod ("Add", new Type[] { listItemType });
283 if (addMethod == null)
284 throw CreateMissingAddMethodException (type, "ICollection",
287 else // at this point, we must be dealing with IEnumerable implementation
289 MethodInfo met = type.GetMethod ("GetEnumerator", Type.EmptyTypes);
291 // get private implemenation
292 met = type.GetMethod ("System.Collections.IEnumerable.GetEnumerator",
293 BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance,
294 null, Type.EmptyTypes, null);
296 // determine ListItemType using IEnumerator.Current property
297 PropertyInfo prop = met.ReturnType.GetProperty ("Current");
299 listItemType = typeof (object);
301 listItemType = prop.PropertyType;
303 MethodInfo addMethod = type.GetMethod ("Add", new Type[] { listItemType });
304 if (addMethod == null)
305 throw CreateMissingAddMethodException (type, "IEnumerable",
313 public TypeData ListTypeData
317 if (listTypeData != null) return listTypeData;
319 listTypeData = new TypeData (TypeName + "[]",
321 TypeTranslator.GetArrayName(XmlType),
322 SchemaTypes.Array, this);
328 public bool IsXsdType {
329 get { return mappedType == null; }
332 public TypeData MappedType {
334 return mappedType != null ? mappedType : this;
338 public XmlSchemaPatternFacet XmlSchemaPatternFacet {
344 public bool HasPublicConstructor
346 get { return hasPublicConstructor; }
350 public static PropertyInfo GetIndexerProperty (Type collectionType)
352 PropertyInfo[] props = collectionType.GetProperties (BindingFlags.Instance | BindingFlags.Public);
353 foreach (PropertyInfo prop in props)
355 ParameterInfo[] pi = prop.GetIndexParameters ();
356 if (pi != null && pi.Length == 1 && pi[0].ParameterType == typeof(int))
362 private static InvalidOperationException CreateMissingAddMethodException (Type type, string inheritFrom, Type argumentType) {
363 return new InvalidOperationException (string.Format(CultureInfo.InvariantCulture,
364 "To be XML serializable, types which inherit from {0} must have " +
365 "an implementation of Add({1}) at all levels of their inheritance " +
366 "hierarchy. {2} does not implement Add({1}).", inheritFrom,
367 argumentType.FullName, type.FullName));