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;
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)
64 this.mappedType = mappedType;
67 this.typeName = type.Name;
68 this.fullTypeName = type.FullName.Replace ('+', '.');
71 sType = SchemaTypes.Primitive;
75 sType = SchemaTypes.Enum;
76 else if (typeof(IXmlSerializable).IsAssignableFrom (type))
77 sType = SchemaTypes.XmlSerializable;
78 else if (typeof (System.Xml.XmlNode).IsAssignableFrom (type))
79 sType = SchemaTypes.XmlNode;
80 else if (type.IsArray || typeof(IEnumerable).IsAssignableFrom (type))
81 sType = SchemaTypes.Array;
83 sType = SchemaTypes.Class;
87 this.elementName = TypeTranslator.GetArrayName (ListItemTypeData.XmlType);
89 this.elementName = elementName;
91 if (sType == SchemaTypes.Array || sType == SchemaTypes.Class) {
92 hasPublicConstructor = !type.IsInterface && (type.IsArray || type.GetConstructor (Type.EmptyTypes) != null || type.IsAbstract || type.IsValueType);
96 internal TypeData (string typeName, string fullTypeName, string xmlType, SchemaTypes schemaType, TypeData listItemTypeData)
98 this.elementName = xmlType;
99 this.typeName = typeName;
100 this.fullTypeName = fullTypeName.Replace ('+', '.');
101 this.listItemTypeData = listItemTypeData;
102 this.sType = schemaType;
103 this.hasPublicConstructor = true;
106 public string TypeName
113 public string XmlType
127 public string FullTypeName
134 public string CSharpName
137 if (csharpName == null)
138 csharpName = (Type == null) ? TypeName : ToCSharpName (Type, false);
143 public string CSharpFullName
146 if (csharpFullName == null)
147 csharpFullName = (Type == null) ? TypeName : ToCSharpName (Type, true);
148 return csharpFullName;
152 // static Microsoft.CSharp.CSharpCodeProvider csprovider =
153 // new Microsoft.CSharp.CSharpCodeProvider ();
155 public static string ToCSharpName (Type type, bool full)
157 // return csprovider.GetTypeOutput (new System.CodeDom.CodeTypeReference (type));
159 StringBuilder sb = new StringBuilder ();
160 sb.Append (ToCSharpName (type.GetElementType (), full));
162 int rank = type.GetArrayRank ();
163 for (int i = 1; i < rank; i++)
166 return sb.ToString ();
169 if (type.IsGenericType && !type.IsGenericTypeDefinition) {
170 StringBuilder sb = new StringBuilder ();
171 sb.Append (ToCSharpName (type.GetGenericTypeDefinition (), full));
173 foreach (Type arg in type.GetGenericArguments ())
174 sb.Append (ToCSharpName (arg, full)).Append (',');
177 return sb.ToString ();
180 string name = full ? type.FullName : type.Name;
181 name = name.Replace ('+', '.');
182 int idx = name.IndexOf ('`'); // generic definition has extra `n.
183 return idx > 0 ? name.Substring (0, idx) : name;
186 public SchemaTypes SchemaType
193 public bool IsListType
195 get { return SchemaType == SchemaTypes.Array; }
198 public bool IsComplexType
202 return (SchemaType == SchemaTypes.Class ||
203 SchemaType == SchemaTypes.Array ||
204 SchemaType == SchemaTypes.Enum ||
205 SchemaType == SchemaTypes.XmlNode ||
206 SchemaType == SchemaTypes.XmlSerializable ||
211 public bool IsValueType
215 if (type != null) return type.IsValueType;
216 else return (sType == SchemaTypes.Primitive || sType == SchemaTypes.Enum);
220 public bool IsNullable
227 return !IsValueType ||
229 type.IsGenericType &&
230 type.GetGenericTypeDefinition () == typeof (Nullable<>));
237 public bool IsGenericNullable
241 genericNullable = value;
245 public TypeData ListItemTypeData
249 if (listItemTypeData == null && type != null)
250 listItemTypeData = TypeTranslator.GetTypeData (ListItemType);
251 return listItemTypeData;
255 public Type ListItemType
260 throw new InvalidOperationException ("Property ListItemType is not supported for custom types");
262 if (listItemType != null) return listItemType;
264 if (SchemaType != SchemaTypes.Array)
265 throw new InvalidOperationException (Type.FullName + " is not a collection");
266 else if (type.IsArray)
267 listItemType = type.GetElementType ();
268 else if (typeof(ICollection).IsAssignableFrom (type))
270 if (typeof (IDictionary).IsAssignableFrom (type))
271 throw new NotSupportedException (string.Format (CultureInfo.InvariantCulture,
272 "The type {0} is not supported because it implements" +
273 " IDictionary.", type.FullName));
275 PropertyInfo prop = GetIndexerProperty (type);
277 throw new InvalidOperationException ("You must implement a default accessor on " + type.FullName + " because it inherits from ICollection");
279 listItemType = prop.PropertyType;
281 MethodInfo addMethod = type.GetMethod ("Add", new Type[] { listItemType });
282 if (addMethod == null)
283 throw CreateMissingAddMethodException (type, "ICollection",
286 else // at this point, we must be dealing with IEnumerable implementation
288 MethodInfo met = type.GetMethod ("GetEnumerator", Type.EmptyTypes);
290 // get private implemenation
291 met = type.GetMethod ("System.Collections.IEnumerable.GetEnumerator",
292 BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance,
293 null, Type.EmptyTypes, null);
295 // determine ListItemType using IEnumerator.Current property
296 PropertyInfo prop = met.ReturnType.GetProperty ("Current");
298 listItemType = typeof (object);
300 listItemType = prop.PropertyType;
302 MethodInfo addMethod = type.GetMethod ("Add", new Type[] { listItemType });
303 if (addMethod == null)
304 throw CreateMissingAddMethodException (type, "IEnumerable",
312 public TypeData ListTypeData
316 if (listTypeData != null) return listTypeData;
318 listTypeData = new TypeData (TypeName + "[]",
320 TypeTranslator.GetArrayName(XmlType),
321 SchemaTypes.Array, this);
327 public bool IsXsdType {
328 get { return mappedType == null; }
331 public TypeData MappedType {
333 return mappedType != null ? mappedType : this;
337 public XmlSchemaPatternFacet XmlSchemaPatternFacet {
343 public bool HasPublicConstructor
345 get { return hasPublicConstructor; }
349 public static PropertyInfo GetIndexerProperty (Type collectionType)
351 PropertyInfo[] props = collectionType.GetProperties (BindingFlags.Instance | BindingFlags.Public);
352 foreach (PropertyInfo prop in props)
354 ParameterInfo[] pi = prop.GetIndexParameters ();
355 if (pi != null && pi.Length == 1 && pi[0].ParameterType == typeof(int))
361 private static InvalidOperationException CreateMissingAddMethodException (Type type, string inheritFrom, Type argumentType) {
362 return new InvalidOperationException (string.Format(CultureInfo.InvariantCulture,
363 "To be XML serializable, types which inherit from {0} must have " +
364 "an implementation of Add({1}) at all levels of their inheritance " +
365 "hierarchy. {2} does not implement Add({1}).", inheritFrom,
366 argumentType.FullName, type.FullName));