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
;
36 using System
.Collections
.Generic
;
38 using System
.Globalization
;
39 using System
.Reflection
;
41 using System
.Xml
.Schema
;
43 namespace System
.Xml
.Serialization
45 internal class TypeData
54 string csharpFullName
;
55 TypeData listItemTypeData
;
56 TypeData listTypeData
;
58 XmlSchemaPatternFacet facet
;
59 bool hasPublicConstructor
= true;
60 bool nullableOverride
;
62 public TypeData (Type type
, string elementName
, bool isPrimitive
) :
63 this(type
, elementName
, isPrimitive
, null, null) {}
65 public TypeData (Type type
, string elementName
, bool isPrimitive
, TypeData mappedType
, XmlSchemaPatternFacet facet
)
68 if (type
.IsGenericTypeDefinition
)
69 throw new InvalidOperationException ("Generic type definition cannot be used in serialization. Only specific generic types can be used.");
71 this.mappedType
= mappedType
;
74 this.typeName
= type
.Name
;
75 this.fullTypeName
= type
.FullName
.Replace ('+', '.');
78 sType
= SchemaTypes
.Primitive
;
82 sType
= SchemaTypes
.Enum
;
83 else if (typeof(IXmlSerializable
).IsAssignableFrom (type
))
84 sType
= SchemaTypes
.XmlSerializable
;
85 else if (typeof (System
.Xml
.XmlNode
).IsAssignableFrom (type
))
86 sType
= SchemaTypes
.XmlNode
;
87 else if (type
.IsArray
|| typeof(IEnumerable
).IsAssignableFrom (type
))
88 sType
= SchemaTypes
.Array
;
90 sType
= SchemaTypes
.Class
;
94 this.elementName
= TypeTranslator
.GetArrayName (ListItemTypeData
.XmlType
);
96 this.elementName
= elementName
;
98 if (sType
== SchemaTypes
.Array
|| sType
== SchemaTypes
.Class
) {
99 hasPublicConstructor
= !type
.IsInterface
&& (type
.IsArray
|| type
.GetConstructor (Type
.EmptyTypes
) != null || type
.IsAbstract
|| type
.IsValueType
);
103 internal TypeData (string typeName
, string fullTypeName
, string xmlType
, SchemaTypes schemaType
, TypeData listItemTypeData
)
105 this.elementName
= xmlType
;
106 this.typeName
= typeName
;
107 this.fullTypeName
= fullTypeName
.Replace ('+', '.');
108 this.listItemTypeData
= listItemTypeData
;
109 this.sType
= schemaType
;
110 this.hasPublicConstructor
= true;
113 public string TypeName
120 public string XmlType
134 public string FullTypeName
141 public string CSharpName
144 if (csharpName
== null)
145 csharpName
= (Type
== null) ? TypeName
: ToCSharpName (Type
, false);
150 public string CSharpFullName
153 if (csharpFullName
== null)
154 csharpFullName
= (Type
== null) ? TypeName
: ToCSharpName (Type
, true);
155 return csharpFullName
;
159 // static Microsoft.CSharp.CSharpCodeProvider csprovider =
160 // new Microsoft.CSharp.CSharpCodeProvider ();
162 public static string ToCSharpName (Type type
, bool full
)
164 // return csprovider.GetTypeOutput (new System.CodeDom.CodeTypeReference (type));
166 StringBuilder sb
= new StringBuilder ();
167 sb
.Append (ToCSharpName (type
.GetElementType (), full
));
169 int rank
= type
.GetArrayRank ();
170 for (int i
= 1; i
< rank
; i
++)
173 return sb
.ToString ();
176 if (type
.IsGenericType
&& !type
.IsGenericTypeDefinition
) {
177 StringBuilder sb
= new StringBuilder ();
178 sb
.Append (ToCSharpName (type
.GetGenericTypeDefinition (), full
));
180 foreach (Type arg
in type
.GetGenericArguments ())
181 sb
.Append (ToCSharpName (arg
, full
)).Append (',');
184 return sb
.ToString ();
187 string name
= full
? type
.FullName
: type
.Name
;
188 name
= name
.Replace ('+', '.');
189 int idx
= name
.IndexOf ('`'); // generic definition has extra `n.
190 name
= idx
> 0 ? name
.Substring (0, idx
) : name
;
191 if (IsKeyword (name
))
197 static bool IsKeyword (string name
)
199 if (keywordsTable
== null) {
200 Hashtable t
= new Hashtable ();
201 foreach (string s
in keywords
)
205 return keywordsTable
.Contains (name
);
208 public SchemaTypes SchemaType
215 public bool IsListType
217 get { return SchemaType == SchemaTypes.Array; }
220 public bool IsComplexType
224 return (SchemaType
== SchemaTypes
.Class
||
225 SchemaType
== SchemaTypes
.Array
||
226 SchemaType
== SchemaTypes
.Enum
||
227 SchemaType
== SchemaTypes
.XmlNode
||
228 SchemaType
== SchemaTypes
.XmlSerializable
||
233 public bool IsValueType
237 if (type
!= null) return type
.IsValueType
;
238 else return (sType
== SchemaTypes
.Primitive
|| sType
== SchemaTypes
.Enum
);
242 public bool NullableOverride
244 get { return nullableOverride; }
247 public bool IsNullable
251 if (nullableOverride
)
254 return !IsValueType
||
256 type
.IsGenericType
&&
257 type
.GetGenericTypeDefinition () == typeof (Nullable
<>));
265 nullableOverride
= value;
269 public TypeData ListItemTypeData
273 if (listItemTypeData
== null && type
!= null)
274 listItemTypeData
= TypeTranslator
.GetTypeData (ListItemType
);
275 return listItemTypeData
;
279 public Type ListItemType
284 throw new InvalidOperationException ("Property ListItemType is not supported for custom types");
286 if (listItemType
!= null) return listItemType
;
288 Type genericArgument
= null;
290 if (SchemaType
!= SchemaTypes
.Array
)
291 throw new InvalidOperationException (Type
.FullName
+ " is not a collection");
292 else if (type
.IsArray
)
293 listItemType
= type
.GetElementType ();
295 else if (typeof (ICollection
).IsAssignableFrom (type
) || (genericArgument
= GetGenericListItemType (type
)) != null)
297 else if (typeof (ICollection
).IsAssignableFrom (type
))
300 if (typeof (IDictionary
).IsAssignableFrom (type
))
301 throw new NotSupportedException (string.Format (CultureInfo
.InvariantCulture
,
302 "The type {0} is not supported because it implements" +
303 " IDictionary.", type
.FullName
));
305 if (genericArgument
!= null)
306 listItemType
= genericArgument
;
308 PropertyInfo prop
= GetIndexerProperty (type
);
310 throw new InvalidOperationException ("You must implement a default accessor on " + type
.FullName
+ " because it inherits from ICollection");
311 listItemType
= prop
.PropertyType
;
314 MethodInfo addMethod
= type
.GetMethod ("Add", new Type
[] { listItemType }
);
315 if (addMethod
== null)
316 throw CreateMissingAddMethodException (type
, "ICollection",
319 else // at this point, we must be dealing with IEnumerable implementation
321 MethodInfo met
= type
.GetMethod ("GetEnumerator", Type
.EmptyTypes
);
323 // get private implemenation
324 met
= type
.GetMethod ("System.Collections.IEnumerable.GetEnumerator",
325 BindingFlags
.NonPublic
| BindingFlags
.Public
| BindingFlags
.Instance
,
326 null, Type
.EmptyTypes
, null);
328 // determine ListItemType using IEnumerator.Current property
329 PropertyInfo prop
= met
.ReturnType
.GetProperty ("Current");
331 listItemType
= typeof (object);
333 listItemType
= prop
.PropertyType
;
335 MethodInfo addMethod
= type
.GetMethod ("Add", new Type
[] { listItemType }
);
336 if (addMethod
== null)
337 throw CreateMissingAddMethodException (type
, "IEnumerable",
345 public TypeData ListTypeData
349 if (listTypeData
!= null) return listTypeData
;
351 listTypeData
= new TypeData (TypeName
+ "[]",
353 TypeTranslator
.GetArrayName(XmlType
),
354 SchemaTypes
.Array
, this);
360 public bool IsXsdType
{
361 get { return mappedType == null; }
364 public TypeData MappedType
{
366 return mappedType
!= null ? mappedType
: this;
370 public XmlSchemaPatternFacet XmlSchemaPatternFacet
{
376 public bool HasPublicConstructor
378 get { return hasPublicConstructor; }
382 public static PropertyInfo
GetIndexerProperty (Type collectionType
)
384 PropertyInfo
[] props
= collectionType
.GetProperties (BindingFlags
.Instance
| BindingFlags
.Public
);
385 foreach (PropertyInfo prop
in props
)
387 ParameterInfo
[] pi
= prop
.GetIndexParameters ();
388 if (pi
!= null && pi
.Length
== 1 && pi
[0].ParameterType
== typeof(int))
394 private static InvalidOperationException
CreateMissingAddMethodException (Type type
, string inheritFrom
, Type argumentType
) {
395 return new InvalidOperationException (string.Format(CultureInfo
.InvariantCulture
,
396 "To be XML serializable, types which inherit from {0} must have " +
397 "an implementation of Add({1}) at all levels of their inheritance " +
398 "hierarchy. {2} does not implement Add({1}).", inheritFrom
,
399 argumentType
.FullName
, type
.FullName
));
402 private static Hashtable keywordsTable
;
403 private static string[] keywords
= new string[] {
404 "abstract","event","new","struct","as","explicit","null","switch","base","extern",
405 "this","false","operator","throw","break","finally","out","true",
406 "fixed","override","try","case","params","typeof","catch","for",
407 "private","foreach","protected","checked","goto","public",
408 "unchecked","class","if","readonly","unsafe","const","implicit","ref",
409 "continue","in","return","using","virtual","default",
410 "interface","sealed","volatile","delegate","internal","do","is",
411 "sizeof","while","lock","stackalloc","else","static","enum",
413 "object","bool","byte","float","uint","char","ulong","ushort",
414 "decimal","int","sbyte","short","double","long","string","void",
416 "partial", "yield", "where"
421 private Type
GetGenericListItemType (Type type
)
423 if (type
.IsGenericType
&& type
.GetGenericTypeDefinition () == typeof (ICollection
<>))
424 return type
.GetGenericArguments () [0];
426 foreach (Type i
in type
.GetInterfaces ())
427 if ((t
= GetGenericListItemType (i
)) != null)