1 //------------------------------------------------------------------------------
2 // <copyright file="XmlReflectionImporter.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 // <owner current="true" primary="true">Microsoft</owner>
6 //------------------------------------------------------------------------------
8 namespace System.Xml.Serialization {
10 using System.Reflection;
12 using System.Xml.Schema;
13 using System.Collections;
14 using System.ComponentModel;
15 using System.Globalization;
16 using System.CodeDom.Compiler;
17 using System.Threading;
18 using System.Diagnostics;
20 /// <include file='doc\XmlReflectionImporter.uex' path='docs/doc[@for="XmlReflectionImporter"]/*' />
23 /// <para>[To be supplied.]</para>
25 public class XmlReflectionImporter {
27 XmlAttributeOverrides attributeOverrides;
28 XmlAttributes defaultAttributes = new XmlAttributes();
29 NameTable types = new NameTable(); // xmltypename + xmlns -> Mapping
30 NameTable nullables = new NameTable(); // xmltypename + xmlns -> NullableMapping
31 NameTable elements = new NameTable(); // xmlelementname + xmlns -> ElementAccessor
32 NameTable xsdAttributes; // xmlattributetname + xmlns -> AttributeAccessor
33 Hashtable specials; // type -> SpecialMapping
34 Hashtable anonymous = new Hashtable(); // type -> AnonymousMapping
35 NameTable serializables; // type name --> new SerializableMapping
38 ModelScope modelScope;
39 int arrayNestingLevel;
40 XmlArrayItemAttributes savedArrayItemAttributes;
41 string savedArrayNamespace;
50 /// <include file='doc\XmlReflectionImporter.uex' path='docs/doc[@for="XmlReflectionImporter.XmlReflectionImporter"]/*' />
52 /// <para>[To be supplied.]</para>
54 public XmlReflectionImporter() : this(null, null) {
57 /// <include file='doc\XmlReflectionImporter.uex' path='docs/doc[@for="XmlReflectionImporter.XmlReflectionImporter1"]/*' />
59 /// <para>[To be supplied.]</para>
61 public XmlReflectionImporter(string defaultNamespace) : this(null, defaultNamespace) {
64 /// <include file='doc\XmlReflectionImporter.uex' path='docs/doc[@for="XmlReflectionImporter.XmlReflectionImporter2"]/*' />
66 /// <para>[To be supplied.]</para>
68 public XmlReflectionImporter(XmlAttributeOverrides attributeOverrides) : this(attributeOverrides, null) {
71 /// <include file='doc\XmlReflectionImporter.uex' path='docs/doc[@for="XmlReflectionImporter.XmlReflectionImporter3"]/*' />
73 /// <para>[To be supplied.]</para>
75 public XmlReflectionImporter(XmlAttributeOverrides attributeOverrides, string defaultNamespace) {
76 if (defaultNamespace == null)
77 defaultNamespace = String.Empty;
78 if (attributeOverrides == null)
79 attributeOverrides = new XmlAttributeOverrides();
80 this.attributeOverrides = attributeOverrides;
81 this.defaultNs = defaultNamespace;
82 this.typeScope = new TypeScope();
83 this.modelScope = new ModelScope(this.typeScope);
86 /// <include file='doc\XmlReflectionImporter.uex' path='docs/doc[@for="XmlReflectionImporter.IncludeTypes"]/*' />
88 /// <para>[To be supplied.]</para>
90 public void IncludeTypes(ICustomAttributeProvider provider) {
91 IncludeTypes(provider, new RecursionLimiter());
94 void IncludeTypes(ICustomAttributeProvider provider, RecursionLimiter limiter) {
95 object[] attrs = provider.GetCustomAttributes(typeof(XmlIncludeAttribute), false);
96 for (int i = 0; i < attrs.Length; i++) {
97 Type type = ((XmlIncludeAttribute)attrs[i]).Type;
98 IncludeType(type, limiter);
102 /// <include file='doc\XmlReflectionImporter.uex' path='docs/doc[@for="XmlReflectionImporter.IncludeType"]/*' />
104 /// <para>[To be supplied.]</para>
106 public void IncludeType(Type type) {
107 IncludeType(type, new RecursionLimiter());
110 void IncludeType(Type type, RecursionLimiter limiter) {
111 int previousNestingLevel = arrayNestingLevel;
112 XmlArrayItemAttributes previousArrayItemAttributes = savedArrayItemAttributes;
113 string previousArrayNamespace = savedArrayNamespace;
114 arrayNestingLevel = 0;
115 savedArrayItemAttributes = null;
116 savedArrayNamespace = null;
118 TypeMapping mapping = ImportTypeMapping(modelScope.GetTypeModel(type), defaultNs, ImportContext.Element, string.Empty, null, limiter);
119 if (mapping.IsAnonymousType && !mapping.TypeDesc.IsSpecial) {
120 //XmlAnonymousInclude=Cannot include anonymous type '{0}'.
121 throw new InvalidOperationException(Res.GetString(Res.XmlAnonymousInclude, type.FullName));
123 arrayNestingLevel = previousNestingLevel;
124 savedArrayItemAttributes = previousArrayItemAttributes;
125 savedArrayNamespace = previousArrayNamespace;
128 /// <include file='doc\XmlReflectionImporter.uex' path='docs/doc[@for="XmlReflectionImporter.ImportTypeMapping"]/*' />
130 /// <para>[To be supplied.]</para>
132 public XmlTypeMapping ImportTypeMapping(Type type) {
133 return ImportTypeMapping(type, null, null);
136 /// <include file='doc\XmlReflectionImporter.uex' path='docs/doc[@for="XmlReflectionImporter.ImportTypeMapping1"]/*' />
138 /// <para>[To be supplied.]</para>
140 public XmlTypeMapping ImportTypeMapping(Type type, string defaultNamespace) {
141 return ImportTypeMapping(type, null, defaultNamespace);
144 /// <include file='doc\XmlReflectionImporter.uex' path='docs/doc[@for="XmlReflectionImporter.ImportTypeMapping2"]/*' />
146 /// <para>[To be supplied.]</para>
148 public XmlTypeMapping ImportTypeMapping(Type type, XmlRootAttribute root) {
149 return ImportTypeMapping(type, root, null);
152 /// <include file='doc\XmlReflectionImporter.uex' path='docs/doc[@for="XmlReflectionImporter.ImportTypeMapping3"]/*' />
154 /// <para>[To be supplied.]</para>
156 public XmlTypeMapping ImportTypeMapping(Type type, XmlRootAttribute root, string defaultNamespace) {
158 throw new ArgumentNullException("type");
159 XmlTypeMapping xmlMapping = new XmlTypeMapping(typeScope, ImportElement(modelScope.GetTypeModel(type), root, defaultNamespace, new RecursionLimiter()));
160 xmlMapping.SetKeyInternal(XmlMapping.GenerateKey(type, root, defaultNamespace));
161 xmlMapping.GenerateSerializer = true;
165 /// <include file='doc\XmlReflectionImporter.uex' path='docs/doc[@for="XmlReflectionImporter.ImportMembersMapping"]/*' />
167 /// <para>[To be supplied.]</para>
169 public XmlMembersMapping ImportMembersMapping(string elementName, string ns, XmlReflectionMember[] members, bool hasWrapperElement) {
170 return ImportMembersMapping(elementName, ns, members, hasWrapperElement, false);
173 /// <include file='doc\XmlReflectionImporter.uex' path='docs/doc[@for="XmlReflectionImporter.ImportMembersMapping1"]/*' />
175 /// <para>[To be supplied.]</para>
177 public XmlMembersMapping ImportMembersMapping(string elementName, string ns, XmlReflectionMember[] members, bool hasWrapperElement, bool rpc) {
178 return ImportMembersMapping(elementName, ns, members, hasWrapperElement, rpc, false);
181 /// <include file='doc\XmlReflectionImporter.uex' path='docs/doc[@for="XmlReflectionImporter.ImportMembersMapping2"]/*' />
183 /// <para>[To be supplied.]</para>
186 public XmlMembersMapping ImportMembersMapping(string elementName, string ns, XmlReflectionMember[] members, bool hasWrapperElement, bool rpc, bool openModel) {
187 return ImportMembersMapping(elementName, ns, members, hasWrapperElement, rpc, openModel, XmlMappingAccess.Read | XmlMappingAccess.Write);
190 /// <include file='doc\XmlReflectionImporter.uex' path='docs/doc[@for="XmlReflectionImporter.ImportMembersMapping3"]/*' />
192 /// <para>[To be supplied.]</para>
195 public XmlMembersMapping ImportMembersMapping(string elementName, string ns, XmlReflectionMember[] members, bool hasWrapperElement, bool rpc, bool openModel, XmlMappingAccess access) {
196 ElementAccessor element = new ElementAccessor();
197 element.Name = elementName == null || elementName.Length == 0 ? elementName : XmlConvert.EncodeLocalName(elementName);
198 element.Namespace = ns;
200 MembersMapping membersMapping = ImportMembersMapping(members, ns, hasWrapperElement, rpc, openModel, new RecursionLimiter());
201 element.Mapping = membersMapping;
202 element.Form = XmlSchemaForm.Qualified; // elements within soap:body are always qualified
204 if (hasWrapperElement)
205 element = (ElementAccessor)ReconcileAccessor(element, this.elements);
207 foreach (MemberMapping mapping in membersMapping.Members) {
208 if (mapping.Elements != null && mapping.Elements.Length > 0) {
209 mapping.Elements[0] = (ElementAccessor)ReconcileAccessor(mapping.Elements[0], this.elements);
214 XmlMembersMapping xmlMapping = new XmlMembersMapping(typeScope, element, access);
215 xmlMapping.GenerateSerializer = true;
219 XmlAttributes GetAttributes(Type type, bool canBeSimpleType) {
220 XmlAttributes attrs = attributeOverrides[type];
221 if (attrs != null) return attrs;
222 if (canBeSimpleType && TypeScope.IsKnownType(type)) {
223 return defaultAttributes;
225 return new XmlAttributes(type);
228 XmlAttributes GetAttributes(MemberInfo memberInfo) {
229 XmlAttributes attrs = attributeOverrides[memberInfo.DeclaringType, memberInfo.Name];
230 if (attrs != null) return attrs;
231 return new XmlAttributes(memberInfo);
234 ElementAccessor ImportElement(TypeModel model, XmlRootAttribute root, string defaultNamespace, RecursionLimiter limiter) {
235 XmlAttributes a = GetAttributes(model.Type, true);
239 string ns = root == null ? null : root.Namespace;
240 if (ns == null) ns = defaultNamespace;
241 if (ns == null) ns = this.defaultNs;
243 arrayNestingLevel = -1;
244 savedArrayItemAttributes = null;
245 savedArrayNamespace = null;
246 ElementAccessor element = CreateElementAccessor(ImportTypeMapping(model, ns, ImportContext.Element, string.Empty, a, limiter), ns);
249 if (root.ElementName.Length > 0)
250 element.Name = XmlConvert.EncodeLocalName(root.ElementName);
251 if (root.IsNullableSpecified && !root.IsNullable && model.TypeDesc.IsOptionalValue)
252 //XmlInvalidNotNullable=IsNullable may not be set to 'false' for a Nullable<{0}> type. Consider using '{0}' type or removing the IsNullable property from the XmlElement attribute.
253 throw new InvalidOperationException(Res.GetString(Res.XmlInvalidNotNullable, model.TypeDesc.BaseTypeDesc.FullName, "XmlRoot"));
254 element.IsNullable = root.IsNullableSpecified ? root.IsNullable : model.TypeDesc.IsNullable || model.TypeDesc.IsOptionalValue;
255 CheckNullable(element.IsNullable, model.TypeDesc, element.Mapping);
258 element.IsNullable = model.TypeDesc.IsNullable || model.TypeDesc.IsOptionalValue;
259 element.Form = XmlSchemaForm.Qualified;
260 return (ElementAccessor)ReconcileAccessor(element, this.elements);
263 static string GetMappingName(Mapping mapping) {
264 if (mapping is MembersMapping)
266 else if (mapping is TypeMapping)
267 return ((TypeMapping)mapping).TypeDesc.FullName;
269 throw new ArgumentException(Res.GetString(Res.XmlInternalError), "mapping");
272 ElementAccessor ReconcileLocalAccessor(ElementAccessor accessor, string ns) {
273 if (accessor.Namespace == ns) return accessor;
274 return (ElementAccessor)ReconcileAccessor(accessor, this.elements);
277 Accessor ReconcileAccessor(Accessor accessor, NameTable accessors) {
278 if (accessor.Any && accessor.Name.Length == 0)
281 Accessor existing = (Accessor)accessors[accessor.Name, accessor.Namespace];
282 if (existing == null) {
283 accessor.IsTopLevelInSchema = true;
284 accessors.Add(accessor.Name, accessor.Namespace, accessor);
288 if (existing.Mapping == accessor.Mapping)
291 if (!(accessor.Mapping is MembersMapping) && !(existing.Mapping is MembersMapping)) {
292 if (accessor.Mapping.TypeDesc == existing.Mapping.TypeDesc
293 || (existing.Mapping is NullableMapping && accessor.Mapping.TypeDesc == ((NullableMapping)existing.Mapping).BaseMapping.TypeDesc)
294 || (accessor.Mapping is NullableMapping && ((NullableMapping)accessor.Mapping).BaseMapping.TypeDesc == existing.Mapping.TypeDesc))
296 // need to compare default values
297 string value1 = Convert.ToString(accessor.Default, CultureInfo.InvariantCulture);
298 string value2 = Convert.ToString(existing.Default, CultureInfo.InvariantCulture);
299 if (value1 == value2) {
302 throw new InvalidOperationException(Res.GetString(Res.XmlCannotReconcileAccessorDefault, accessor.Name, accessor.Namespace, value1, value2));
306 if (accessor.Mapping is MembersMapping || existing.Mapping is MembersMapping)
307 throw new InvalidOperationException(Res.GetString(Res.XmlMethodTypeNameConflict, accessor.Name, accessor.Namespace));
309 if (accessor.Mapping is ArrayMapping) {
310 if (!(existing.Mapping is ArrayMapping)) {
311 throw new InvalidOperationException(Res.GetString(Res.XmlCannotReconcileAccessor, accessor.Name, accessor.Namespace, GetMappingName(existing.Mapping), GetMappingName(accessor.Mapping)));
313 ArrayMapping mapping = (ArrayMapping)accessor.Mapping;
314 ArrayMapping existingMapping = mapping.IsAnonymousType ? null : (ArrayMapping)types[existing.Mapping.TypeName, existing.Mapping.Namespace];
315 ArrayMapping first = existingMapping;
316 while (existingMapping != null) {
317 if (existingMapping == accessor.Mapping)
319 existingMapping = existingMapping.Next;
321 mapping.Next = first;
322 if (!mapping.IsAnonymousType)
323 types[existing.Mapping.TypeName, existing.Mapping.Namespace] = mapping;
326 if (accessor is AttributeAccessor)
327 throw new InvalidOperationException(Res.GetString(Res.XmlCannotReconcileAttributeAccessor, accessor.Name, accessor.Namespace, GetMappingName(existing.Mapping), GetMappingName(accessor.Mapping)));
329 throw new InvalidOperationException(Res.GetString(Res.XmlCannotReconcileAccessor, accessor.Name, accessor.Namespace, GetMappingName(existing.Mapping), GetMappingName(accessor.Mapping)));
332 Exception CreateReflectionException(string context, Exception e) {
333 return new InvalidOperationException(Res.GetString(Res.XmlReflectionError, context), e);
336 Exception CreateTypeReflectionException(string context, Exception e) {
337 return new InvalidOperationException(Res.GetString(Res.XmlTypeReflectionError, context), e);
340 Exception CreateMemberReflectionException(FieldModel model, Exception e) {
341 return new InvalidOperationException(Res.GetString(model.IsProperty ? Res.XmlPropertyReflectionError : Res.XmlFieldReflectionError, model.Name), e);
344 TypeMapping ImportTypeMapping(TypeModel model, string ns, ImportContext context, string dataType, XmlAttributes a, RecursionLimiter limiter) {
345 return ImportTypeMapping(model, ns, context, dataType, a, false, false, limiter);
348 TypeMapping ImportTypeMapping(TypeModel model, string ns, ImportContext context, string dataType, XmlAttributes a, bool repeats, bool openModel, RecursionLimiter limiter) {
350 if (dataType.Length > 0) {
351 TypeDesc modelTypeDesc = TypeScope.IsOptionalValue(model.Type) ? model.TypeDesc.BaseTypeDesc : model.TypeDesc;
352 if (!modelTypeDesc.IsPrimitive) {
353 throw new InvalidOperationException(Res.GetString(Res.XmlInvalidDataTypeUsage, dataType, "XmlElementAttribute.DataType"));
355 TypeDesc td = typeScope.GetTypeDesc(dataType, XmlSchema.Namespace);
357 throw new InvalidOperationException(Res.GetString(Res.XmlInvalidXsdDataType, dataType, "XmlElementAttribute.DataType", new XmlQualifiedName(dataType, XmlSchema.Namespace).ToString()));
359 if (modelTypeDesc.FullName != td.FullName) {
360 throw new InvalidOperationException(Res.GetString(Res.XmlDataTypeMismatch, dataType, "XmlElementAttribute.DataType", modelTypeDesc.FullName));
365 a = GetAttributes(model.Type, false);
367 if ((a.XmlFlags & ~(XmlAttributeFlags.Type | XmlAttributeFlags.Root)) != 0)
368 throw new InvalidOperationException(Res.GetString(Res.XmlInvalidTypeAttributes, model.Type.FullName));
370 switch (model.TypeDesc.Kind) {
372 return ImportEnumMapping((EnumModel)model, ns, repeats);
373 case TypeKind.Primitive:
374 if (a.XmlFlags != 0) throw InvalidAttributeUseException(model.Type);
375 return ImportPrimitiveMapping((PrimitiveModel)model, context, dataType, repeats);
377 case TypeKind.Collection:
378 case TypeKind.Enumerable:
379 //if (a.XmlFlags != 0) throw InvalidAttributeUseException(model.Type);
380 if (context != ImportContext.Element) throw UnsupportedException(model.TypeDesc, context);
382 ArrayMapping arrayMapping = ImportArrayLikeMapping((ArrayModel)model, ns, limiter);
387 case TypeKind.Struct:
388 if (context != ImportContext.Element) throw UnsupportedException(model.TypeDesc, context);
389 if (model.TypeDesc.IsOptionalValue) {
390 TypeDesc valueTypeDesc = string.IsNullOrEmpty(dataType) ? model.TypeDesc.BaseTypeDesc : typeScope.GetTypeDesc(dataType, XmlSchema.Namespace);
391 string xsdTypeName = valueTypeDesc.DataType == null ? valueTypeDesc.Name : valueTypeDesc.DataType.Name;
392 TypeMapping baseMapping = GetTypeMapping(xsdTypeName, ns, valueTypeDesc, types, null);
393 if (baseMapping == null)
394 baseMapping = ImportTypeMapping(modelScope.GetTypeModel(model.TypeDesc.BaseTypeDesc.Type), ns, context, dataType, null, repeats, openModel, limiter);
395 return CreateNullableMapping(baseMapping, model.TypeDesc.Type);
398 return ImportStructLikeMapping((StructModel)model, ns, openModel, a, limiter);
401 if (model.TypeDesc.Kind == TypeKind.Serializable) {
402 // We allow XmlRoot attribute on IXmlSerializable, but not others
403 if ((a.XmlFlags & ~XmlAttributeFlags.Root) != 0) {
404 throw new InvalidOperationException(Res.GetString(Res.XmlSerializableAttributes, model.TypeDesc.FullName, typeof(XmlSchemaProviderAttribute).Name));
408 if (a.XmlFlags != 0) throw InvalidAttributeUseException(model.Type);
410 if (model.TypeDesc.IsSpecial)
411 return ImportSpecialMapping(model.Type, model.TypeDesc, ns, context, limiter);
412 throw UnsupportedException(model.TypeDesc, context);
415 catch (Exception e) {
416 if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException) {
419 throw CreateTypeReflectionException(model.TypeDesc.FullName, e);
423 internal static MethodInfo GetMethodFromSchemaProvider(XmlSchemaProviderAttribute provider, Type type) {
424 if (provider.IsAny) {
425 // do not validate the schema provider method for wildcard types.
428 else if (provider.MethodName == null) {
429 throw new ArgumentNullException("MethodName");
431 if (!CodeGenerator.IsValidLanguageIndependentIdentifier(provider.MethodName))
432 throw new ArgumentException(Res.GetString(Res.XmlGetSchemaMethodName, provider.MethodName), "MethodName");
434 MethodInfo getMethod = getMethod = type.GetMethod(provider.MethodName, /* BindingFlags.DeclaredOnly | */ BindingFlags.Static | BindingFlags.Public, null, new Type[] {typeof(XmlSchemaSet)}, null);
435 if (getMethod == null)
436 throw new InvalidOperationException(Res.GetString(Res.XmlGetSchemaMethodMissing, provider.MethodName, typeof(XmlSchemaSet).Name, type.FullName));
438 if (!(typeof(XmlQualifiedName).IsAssignableFrom(getMethod.ReturnType)) && !(typeof(XmlSchemaType).IsAssignableFrom(getMethod.ReturnType)))
439 throw new InvalidOperationException(Res.GetString(Res.XmlGetSchemaMethodReturnType, type.Name, provider.MethodName, typeof(XmlSchemaProviderAttribute).Name, typeof(XmlQualifiedName).FullName, typeof(XmlSchemaType).FullName));
444 SpecialMapping ImportSpecialMapping(Type type, TypeDesc typeDesc, string ns, ImportContext context, RecursionLimiter limiter) {
445 if (specials == null)
446 specials = new Hashtable();
447 SpecialMapping mapping = (SpecialMapping)specials[type];
448 if (mapping != null) {
449 CheckContext(mapping.TypeDesc, context);
452 if (typeDesc.Kind == TypeKind.Serializable) {
454 SerializableMapping serializableMapping = null;
456 // get the schema method info
457 object[] attrs = type.GetCustomAttributes(typeof(XmlSchemaProviderAttribute), false);
459 if (attrs.Length > 0) {
460 // new IXmlSerializable
461 XmlSchemaProviderAttribute provider = (XmlSchemaProviderAttribute)attrs[0];
462 MethodInfo method = GetMethodFromSchemaProvider(provider, type);
463 serializableMapping = new SerializableMapping(method, provider.IsAny, ns);
464 XmlQualifiedName qname = serializableMapping.XsiType;
465 if (qname != null && !qname.IsEmpty) {
466 if (serializables == null)
467 serializables = new NameTable();
468 SerializableMapping existingMapping = (SerializableMapping)serializables[qname];
469 if (existingMapping != null) {
470 if (existingMapping.Type == null) {
471 serializableMapping = existingMapping;
473 else if (existingMapping.Type != type) {
474 SerializableMapping next = existingMapping.Next;
475 existingMapping.Next = serializableMapping;
476 serializableMapping.Next = next;
480 XmlSchemaType xsdType = serializableMapping.XsdType;
482 SetBase(serializableMapping, xsdType.DerivedFrom);
483 serializables[qname] = serializableMapping;
485 serializableMapping.TypeName = qname.Name;
486 serializableMapping.Namespace = qname.Namespace;
488 serializableMapping.TypeDesc = typeDesc;
489 serializableMapping.Type = type;
493 // old IXmlSerializable
494 serializableMapping = new SerializableMapping();
495 serializableMapping.TypeDesc = typeDesc;
496 serializableMapping.Type = type;
498 mapping = serializableMapping;
501 mapping = new SpecialMapping();
502 mapping.TypeDesc = typeDesc;
504 CheckContext(typeDesc, context);
505 specials.Add(type, mapping);
506 typeScope.AddTypeMapping(mapping);
510 internal static void ValidationCallbackWithErrorCode (object sender, ValidationEventArgs args) {
512 if (args.Severity == XmlSeverityType.Error)
513 throw new InvalidOperationException(Res.GetString(Res.XmlSerializableSchemaError, typeof(IXmlSerializable).Name, args.Message));
516 internal void SetBase(SerializableMapping mapping, XmlQualifiedName baseQname) {
518 if (baseQname.IsEmpty) return;
519 if (baseQname.Namespace == XmlSchema.Namespace) return;
520 XmlSchemaSet schemas = mapping.Schemas;
521 ArrayList srcSchemas = (ArrayList)schemas.Schemas(baseQname.Namespace);
523 if (srcSchemas.Count == 0) {
524 throw new InvalidOperationException(Res.GetString(Res.XmlMissingSchema, baseQname.Namespace));
526 if (srcSchemas.Count > 1) {
527 throw new InvalidOperationException(Res.GetString(Res.XmlGetSchemaInclude, baseQname.Namespace, typeof(IXmlSerializable).Name, "GetSchema"));
529 XmlSchema s = (XmlSchema)srcSchemas[0];
531 XmlSchemaType t = (XmlSchemaType)s.SchemaTypes[baseQname];
532 t = t.Redefined != null ? t.Redefined : t;
534 if (serializables[baseQname] == null) {
535 SerializableMapping baseMapping = new SerializableMapping(baseQname, schemas);
536 SetBase(baseMapping, t.DerivedFrom);
537 serializables.Add(baseQname, baseMapping);
539 mapping.SetBaseMapping((SerializableMapping)serializables[baseQname]);
542 static string GetContextName(ImportContext context) {
544 case ImportContext.Element: return "element";
545 case ImportContext.Attribute: return "attribute";
546 case ImportContext.Text: return "text";
548 throw new ArgumentException(Res.GetString(Res.XmlInternalError), "context");
552 static Exception InvalidAttributeUseException(Type type) {
553 return new InvalidOperationException(Res.GetString(Res.XmlInvalidAttributeUse, type.FullName));
556 static Exception UnsupportedException(TypeDesc typeDesc, ImportContext context) {
557 return new InvalidOperationException(Res.GetString(Res.XmlIllegalTypeContext, typeDesc.FullName, GetContextName(context)));
560 StructMapping CreateRootMapping() {
561 TypeDesc typeDesc = typeScope.GetTypeDesc(typeof(object));
562 StructMapping mapping = new StructMapping();
563 mapping.TypeDesc = typeDesc;
564 mapping.TypeName = Soap.UrType;
565 mapping.Namespace = XmlSchema.Namespace;
566 mapping.Members = new MemberMapping[0];
567 mapping.IncludeInSchema = false;
571 NullableMapping CreateNullableMapping(TypeMapping baseMapping, Type type) {
572 TypeDesc typeDesc = baseMapping.TypeDesc.GetNullableTypeDesc(type);
573 TypeMapping existingMapping;
574 if (!baseMapping.IsAnonymousType)
576 existingMapping = (TypeMapping)nullables[baseMapping.TypeName, baseMapping.Namespace];
580 existingMapping = (TypeMapping)anonymous[type];
583 NullableMapping mapping;
584 if (existingMapping != null) {
585 if (existingMapping is NullableMapping) {
586 mapping = (NullableMapping)existingMapping;
587 if (mapping.BaseMapping is PrimitiveMapping && baseMapping is PrimitiveMapping)
589 else if (mapping.BaseMapping == baseMapping) {
593 throw new InvalidOperationException(Res.GetString(Res.XmlTypesDuplicate, typeDesc.FullName, existingMapping.TypeDesc.FullName, typeDesc.Name, existingMapping.Namespace));
597 throw new InvalidOperationException(Res.GetString(Res.XmlTypesDuplicate, typeDesc.FullName, existingMapping.TypeDesc.FullName, typeDesc.Name, existingMapping.Namespace));
600 mapping = new NullableMapping();
601 mapping.BaseMapping = baseMapping;
602 mapping.TypeDesc = typeDesc;
603 mapping.TypeName = baseMapping.TypeName;
604 mapping.Namespace = baseMapping.Namespace;
605 mapping.IncludeInSchema = baseMapping.IncludeInSchema;
606 if (!baseMapping.IsAnonymousType)
608 nullables.Add(baseMapping.TypeName, baseMapping.Namespace, mapping);
612 anonymous[type] = mapping;
615 typeScope.AddTypeMapping(mapping);
619 StructMapping GetRootMapping() {
621 root = CreateRootMapping();
622 typeScope.AddTypeMapping(root);
627 TypeMapping GetTypeMapping(string typeName, string ns, TypeDesc typeDesc, NameTable typeLib, Type type) {
628 TypeMapping mapping ;
629 if (typeName == null || typeName.Length == 0)
630 mapping = type == null ? null : (TypeMapping)anonymous[type];
632 mapping = (TypeMapping)typeLib[typeName, ns];
634 if (mapping == null) return null;
635 if (!mapping.IsAnonymousType && mapping.TypeDesc != typeDesc)
636 throw new InvalidOperationException(Res.GetString(Res.XmlTypesDuplicate, typeDesc.FullName, mapping.TypeDesc.FullName, typeName, ns));
640 StructMapping ImportStructLikeMapping(StructModel model, string ns, bool openModel, XmlAttributes a, RecursionLimiter limiter) {
641 if (model.TypeDesc.Kind == TypeKind.Root) return GetRootMapping();
643 a = GetAttributes(model.Type, false);
646 if (a.XmlType != null && a.XmlType.Namespace != null)
647 typeNs = a.XmlType.Namespace;
648 else if (a.XmlRoot != null && a.XmlRoot.Namespace != null)
649 typeNs = a.XmlRoot.Namespace;
651 string typeName = IsAnonymousType(a, ns) ? null : XsdTypeName(model.Type, a, model.TypeDesc.Name);
652 typeName = XmlConvert.EncodeLocalName(typeName);
654 StructMapping mapping = (StructMapping)GetTypeMapping(typeName, typeNs, model.TypeDesc, types, model.Type);
655 if (mapping == null) {
656 mapping = new StructMapping();
657 mapping.TypeDesc = model.TypeDesc;
658 mapping.Namespace = typeNs;
659 mapping.TypeName = typeName;
660 if (!mapping.IsAnonymousType)
661 types.Add(typeName, typeNs, mapping);
663 anonymous[model.Type] = mapping;
664 if (a.XmlType != null) {
665 mapping.IncludeInSchema = a.XmlType.IncludeInSchema;
668 if (limiter.IsExceededLimit) {
669 limiter.DeferredWorkItems.Add(new ImportStructWorkItem(model, mapping));
675 InitializeStructMembers(mapping, model, openModel, typeName, limiter);
676 while (limiter.DeferredWorkItems.Count > 0) {
677 int index = limiter.DeferredWorkItems.Count - 1;
678 ImportStructWorkItem item = limiter.DeferredWorkItems[index];
679 if (InitializeStructMembers(item.Mapping, item.Model, openModel, typeName, limiter)) {
681 // if InitializeStructMembers returns true, then there were *no* chages to the DeferredWorkItems
684 // use exception in the place of Debug.Assert to avoid throwing asserts from a server process such as aspnet_ewp.exe
685 if (index != limiter.DeferredWorkItems.Count - 1)
686 throw new InvalidOperationException(Res.GetString(Res.XmlInternalErrorDetails, "DeferredWorkItems.Count have changed"));
687 if (item != limiter.DeferredWorkItems[index])
688 throw new InvalidOperationException(Res.GetString(Res.XmlInternalErrorDetails, "DeferredWorkItems.Top have changed"));
690 // Remove the last work item
691 limiter.DeferredWorkItems.RemoveAt(index);
699 bool InitializeStructMembers(StructMapping mapping, StructModel model, bool openModel, string typeName, RecursionLimiter limiter) {
700 if (mapping.IsFullyInitialized)
703 if (model.TypeDesc.BaseTypeDesc != null) {
704 TypeModel baseModel = modelScope.GetTypeModel(model.Type.BaseType, false);
705 if (!(baseModel is StructModel)) {
706 //XmlUnsupportedInheritance=Using '{0}' as a base type for a class is not supported by XmlSerializer.
707 throw new NotSupportedException(Res.GetString(Res.XmlUnsupportedInheritance, model.Type.BaseType.FullName));
709 StructMapping baseMapping = ImportStructLikeMapping((StructModel)baseModel, mapping.Namespace, openModel, null, limiter);
710 // check to see if the import of the baseMapping was deffered
711 int baseIndex = limiter.DeferredWorkItems.IndexOf(baseMapping);
713 mapping.BaseMapping = baseMapping;
715 ICollection values = mapping.BaseMapping.LocalAttributes.Values;
716 foreach (AttributeAccessor attribute in values) {
717 AddUniqueAccessor(mapping.LocalAttributes, attribute);
719 if (!mapping.BaseMapping.HasExplicitSequence()) {
720 values = mapping.BaseMapping.LocalElements.Values;
721 foreach (ElementAccessor e in values) {
722 AddUniqueAccessor(mapping.LocalElements, e);
727 // the import of the baseMapping was deffered, make sure that the derived mappings is deffered as well
728 if (!limiter.DeferredWorkItems.Contains(mapping)) {
729 limiter.DeferredWorkItems.Add(new ImportStructWorkItem(model, mapping));
731 // make sure that baseMapping get processed before the derived
732 int top = limiter.DeferredWorkItems.Count - 1;
733 if (baseIndex < top) {
734 ImportStructWorkItem baseMappingWorkItem = limiter.DeferredWorkItems[baseIndex];
735 limiter.DeferredWorkItems[baseIndex] = limiter.DeferredWorkItems[top];
736 limiter.DeferredWorkItems[top] = baseMappingWorkItem;
741 ArrayList members = new ArrayList();
742 TextAccessor textAccesor = null;
743 bool hasElements = false;
744 bool isSequence = false;
746 foreach (MemberInfo memberInfo in model.GetMemberInfos()) {
747 if ((memberInfo.MemberType & (MemberTypes.Field | MemberTypes.Property)) == 0)
749 XmlAttributes memberAttrs = GetAttributes(memberInfo);
750 if (memberAttrs.XmlIgnore) continue;
751 FieldModel fieldModel = model.GetFieldModel(memberInfo);
752 if (fieldModel == null) continue;
754 MemberMapping member = ImportFieldMapping(model, fieldModel, memberAttrs, mapping.Namespace, limiter);
755 if (member == null) continue;
756 if (mapping.BaseMapping != null) {
757 if (mapping.BaseMapping.Declares(member, mapping.TypeName)) continue;
759 isSequence |= member.IsSequence;
760 // add All memeber accessors to the scope accessors
761 AddUniqueAccessor(member, mapping.LocalElements, mapping.LocalAttributes, isSequence);
763 if (member.Text != null) {
764 if (!member.Text.Mapping.TypeDesc.CanBeTextValue && member.Text.Mapping.IsList)
765 throw new InvalidOperationException(Res.GetString(Res.XmlIllegalTypedTextAttribute, typeName, member.Text.Name, member.Text.Mapping.TypeDesc.FullName));
766 if (textAccesor != null) {
767 throw new InvalidOperationException(Res.GetString(Res.XmlIllegalMultipleText, model.Type.FullName));
769 textAccesor = member.Text;
771 if (member.Xmlns != null) {
772 if (mapping.XmlnsMember != null)
773 throw new InvalidOperationException(Res.GetString(Res.XmlMultipleXmlns, model.Type.FullName));
774 mapping.XmlnsMember = member;
776 if (member.Elements != null && member.Elements.Length != 0) {
781 catch (Exception e) {
782 if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException) {
785 throw CreateMemberReflectionException(fieldModel, e);
788 mapping.SetContentModel(textAccesor, hasElements);
790 Hashtable ids = new Hashtable();
791 for (int i = 0; i < members.Count; i++) {
792 MemberMapping member = (MemberMapping)members[i];
793 if (!member.IsParticle)
795 if (member.IsSequence) {
796 if (ids[member.SequenceId] != null) {
797 throw new InvalidOperationException(Res.GetString(Res.XmlSequenceUnique, member.SequenceId.ToString(CultureInfo.InvariantCulture), "Order", member.Name));
799 ids[member.SequenceId] = member;
802 throw new InvalidOperationException(Res.GetString(Res.XmlSequenceInconsistent, "Order", member.Name));
805 members.Sort(new MemberMappingComparer());
807 mapping.Members = (MemberMapping[])members.ToArray(typeof(MemberMapping));
809 if (mapping.BaseMapping == null) mapping.BaseMapping = GetRootMapping();
811 if (mapping.XmlnsMember != null && mapping.BaseMapping.HasXmlnsMember)
812 throw new InvalidOperationException(Res.GetString(Res.XmlMultipleXmlns, model.Type.FullName));
814 IncludeTypes(model.Type, limiter);
815 typeScope.AddTypeMapping(mapping);
817 mapping.IsOpenModel = true;
821 static bool IsAnonymousType(XmlAttributes a, string contextNs) {
822 if (a.XmlType != null && a.XmlType.AnonymousType) {
824 // check to see if the anonymous type is used in the original context
825 // only treat it as Anonymous, if the referencing element's namespace
826 // matches the original referencing element, otherwise revert to
827 // non-Anonymous handling for backward compatibility.
829 string originalNs = a.XmlType.Namespace;
830 return string.IsNullOrEmpty(originalNs) || originalNs == contextNs;
835 internal string XsdTypeName(Type type) {
836 if (type == typeof(object)) return Soap.UrType;
837 TypeDesc typeDesc = typeScope.GetTypeDesc(type);
838 if (typeDesc.IsPrimitive && typeDesc.DataType != null && typeDesc.DataType.Name != null && typeDesc.DataType.Name.Length > 0)
839 return typeDesc.DataType.Name;
840 return XsdTypeName(type, GetAttributes(type, false), typeDesc.Name);
843 internal string XsdTypeName(Type type, XmlAttributes a, string name) {
844 string typeName = name;
845 if (a.XmlType != null && a.XmlType.TypeName.Length > 0)
846 typeName = a.XmlType.TypeName;
848 if (type.IsGenericType && typeName.IndexOf('{') >= 0) {
849 Type genType = type.GetGenericTypeDefinition();
850 Type[] names = genType.GetGenericArguments();
851 Type[] types = type.GetGenericArguments();
853 for (int i = 0; i < names.Length; i++) {
854 string argument = "{" + names[i] + "}";
855 if (typeName.Contains(argument)) {
856 typeName = typeName.Replace(argument, XsdTypeName(types[i]));
857 if (typeName.IndexOf('{') < 0) {
867 private static int CountAtLevel(XmlArrayItemAttributes attributes, int level) {
869 for (int i = 0; i < attributes.Count; i++)
870 if (attributes[i].NestingLevel == level) sum++;
874 void SetArrayMappingType(ArrayMapping mapping, string defaultNs, Type type) {
875 XmlAttributes a = GetAttributes(type, false);
876 bool isAnonymous = IsAnonymousType(a, defaultNs);
878 mapping.TypeName = null;
879 mapping.Namespace = defaultNs;
884 TypeMapping itemTypeMapping;
885 ElementAccessor element = null;
887 if (mapping.Elements.Length == 1) {
888 element = mapping.Elements[0];
889 itemTypeMapping = element.Mapping;
892 itemTypeMapping = null;
895 bool generateTypeName = true;
896 if (a.XmlType != null) {
897 ns = a.XmlType.Namespace;
898 name = XsdTypeName(type, a, a.XmlType.TypeName);
899 name = XmlConvert.EncodeLocalName(name);
900 generateTypeName = name == null;
902 else if (itemTypeMapping is EnumMapping) {
903 ns = itemTypeMapping.Namespace;
904 name = itemTypeMapping.DefaultElementName;
906 else if (itemTypeMapping is PrimitiveMapping) {
908 name = itemTypeMapping.TypeDesc.DataType.Name;
910 else if (itemTypeMapping is StructMapping && itemTypeMapping.TypeDesc.IsRoot) {
914 else if (itemTypeMapping != null) {
915 ns = itemTypeMapping.Namespace == XmlSchema.Namespace ? defaultNs : itemTypeMapping.Namespace;
916 name = itemTypeMapping.DefaultElementName;
920 name = "Choice" + (choiceNum++);
927 ns = element.Namespace;
932 string uniqueName = name = generateTypeName ? "ArrayOf" + CodeIdentifier.MakePascal(name) : name;
934 TypeMapping existingMapping = (TypeMapping)types[uniqueName, ns];
935 while (existingMapping != null) {
936 if (existingMapping is ArrayMapping) {
937 ArrayMapping arrayMapping = (ArrayMapping)existingMapping;
938 if (AccessorMapping.ElementsMatch(arrayMapping.Elements, mapping.Elements)) {
942 // need to re-name the mapping
943 uniqueName = name + i.ToString(CultureInfo.InvariantCulture);
944 existingMapping = (TypeMapping)types[uniqueName, ns];
947 mapping.TypeName = uniqueName;
948 mapping.Namespace = ns;
951 ArrayMapping ImportArrayLikeMapping(ArrayModel model, string ns, RecursionLimiter limiter) {
952 ArrayMapping mapping = new ArrayMapping();
953 mapping.TypeDesc = model.TypeDesc;
955 if (savedArrayItemAttributes == null)
956 savedArrayItemAttributes = new XmlArrayItemAttributes();
957 if (CountAtLevel(savedArrayItemAttributes, arrayNestingLevel) == 0)
958 savedArrayItemAttributes.Add(CreateArrayItemAttribute(typeScope.GetTypeDesc(model.Element.Type), arrayNestingLevel));
959 CreateArrayElementsFromAttributes(mapping, savedArrayItemAttributes, model.Element.Type, savedArrayNamespace == null ? ns : savedArrayNamespace, limiter);
960 SetArrayMappingType(mapping, ns, model.Type);
962 // reconcile accessors now that we have the ArrayMapping namespace
963 for (int i = 0; i < mapping.Elements.Length; i++) {
964 mapping.Elements[i] = ReconcileLocalAccessor(mapping.Elements[i], mapping.Namespace);
967 IncludeTypes(model.Type);
969 // in the case of an ArrayMapping we can have more that one mapping correspond to a type
970 // examples of that are ArrayList and object[] both will map tp ArrayOfur-type
971 // so we create a link list for all mappings of the same XSD type
972 ArrayMapping existingMapping = (ArrayMapping)types[mapping.TypeName, mapping.Namespace];
973 if (existingMapping != null) {
974 ArrayMapping first = existingMapping;
975 while (existingMapping != null) {
976 if (existingMapping.TypeDesc == model.TypeDesc)
977 return existingMapping;
978 existingMapping = existingMapping.Next;
980 mapping.Next = first;
981 if (!mapping.IsAnonymousType)
982 types[mapping.TypeName, mapping.Namespace] = mapping;
984 anonymous[model.Type] = mapping;
987 typeScope.AddTypeMapping(mapping);
988 if (!mapping.IsAnonymousType)
989 types.Add(mapping.TypeName, mapping.Namespace, mapping);
991 anonymous[model.Type] = mapping;
995 void CheckContext(TypeDesc typeDesc, ImportContext context) {
997 case ImportContext.Element:
998 if (typeDesc.CanBeElementValue) return;
1000 case ImportContext.Attribute:
1001 if (typeDesc.CanBeAttributeValue) return;
1003 case ImportContext.Text:
1004 if (typeDesc.CanBeTextValue || typeDesc.IsEnum || typeDesc.IsPrimitive)
1008 throw new ArgumentException(Res.GetString(Res.XmlInternalError), "context");
1010 throw UnsupportedException(typeDesc, context);
1013 PrimitiveMapping ImportPrimitiveMapping(PrimitiveModel model, ImportContext context, string dataType, bool repeats) {
1014 PrimitiveMapping mapping = new PrimitiveMapping();
1015 if (dataType.Length > 0) {
1016 mapping.TypeDesc = typeScope.GetTypeDesc(dataType, XmlSchema.Namespace);
1017 if (mapping.TypeDesc == null) {
1018 // try it as a non-Xsd type
1019 mapping.TypeDesc = typeScope.GetTypeDesc(dataType, UrtTypes.Namespace);
1020 if (mapping.TypeDesc == null) {
1021 throw new InvalidOperationException(Res.GetString(Res.XmlUdeclaredXsdType, dataType));
1026 mapping.TypeDesc = model.TypeDesc;
1028 mapping.TypeName = mapping.TypeDesc.DataType.Name;
1029 mapping.Namespace = mapping.TypeDesc.IsXsdType ? XmlSchema.Namespace : UrtTypes.Namespace;
1030 mapping.IsList = repeats;
1031 CheckContext(mapping.TypeDesc, context);
1035 EnumMapping ImportEnumMapping(EnumModel model, string ns, bool repeats) {
1036 XmlAttributes a = GetAttributes(model.Type, false);
1038 if (a.XmlType != null && a.XmlType.Namespace != null)
1039 typeNs = a.XmlType.Namespace;
1041 string typeName = IsAnonymousType(a, ns) ? null : XsdTypeName(model.Type, a, model.TypeDesc.Name);
1042 typeName = XmlConvert.EncodeLocalName(typeName);
1044 EnumMapping mapping = (EnumMapping)GetTypeMapping(typeName, typeNs, model.TypeDesc, types, model.Type);
1045 if (mapping == null) {
1046 mapping = new EnumMapping();
1047 mapping.TypeDesc = model.TypeDesc;
1048 mapping.TypeName = typeName;
1049 mapping.Namespace = typeNs;
1050 mapping.IsFlags = model.Type.IsDefined(typeof(FlagsAttribute), false);
1051 if (mapping.IsFlags && repeats)
1052 throw new InvalidOperationException(Res.GetString(Res.XmlIllegalAttributeFlagsArray, model.TypeDesc.FullName));
1053 mapping.IsList = repeats;
1054 mapping.IncludeInSchema = a.XmlType == null ? true : a.XmlType.IncludeInSchema;
1055 if (!mapping.IsAnonymousType)
1056 types.Add(typeName, typeNs, mapping);
1058 anonymous[model.Type] = mapping;
1059 ArrayList constants = new ArrayList();
1060 for (int i = 0; i < model.Constants.Length; i++) {
1061 ConstantMapping constant = ImportConstantMapping(model.Constants[i]);
1062 if (constant != null) constants.Add(constant);
1064 if (constants.Count == 0) {
1065 throw new InvalidOperationException(Res.GetString(Res.XmlNoSerializableMembers, model.TypeDesc.FullName));
1067 mapping.Constants = (ConstantMapping[])constants.ToArray(typeof(ConstantMapping));
1068 typeScope.AddTypeMapping(mapping);
1073 ConstantMapping ImportConstantMapping(ConstantModel model) {
1074 XmlAttributes a = GetAttributes(model.FieldInfo);
1075 if (a.XmlIgnore) return null;
1076 if ((a.XmlFlags & ~XmlAttributeFlags.Enum) != 0)
1077 throw new InvalidOperationException(Res.GetString(Res.XmlInvalidConstantAttribute));
1078 if (a.XmlEnum == null)
1079 a.XmlEnum = new XmlEnumAttribute();
1081 ConstantMapping constant = new ConstantMapping();
1082 constant.XmlName = a.XmlEnum.Name == null ? model.Name : a.XmlEnum.Name;
1083 constant.Name = model.Name;
1084 constant.Value = model.Value;
1088 MembersMapping ImportMembersMapping(XmlReflectionMember[] xmlReflectionMembers, string ns, bool hasWrapperElement, bool rpc, bool openModel, RecursionLimiter limiter) {
1089 MembersMapping members = new MembersMapping();
1090 members.TypeDesc = typeScope.GetTypeDesc(typeof(object[]));
1091 MemberMapping[] mappings = new MemberMapping[xmlReflectionMembers.Length];
1092 NameTable elements = new NameTable();
1093 NameTable attributes = new NameTable();
1094 TextAccessor textAccessor = null;
1095 bool isSequence = false;
1097 for (int i = 0; i < mappings.Length; i++) {
1099 MemberMapping mapping = ImportMemberMapping(xmlReflectionMembers[i], ns, xmlReflectionMembers, rpc, openModel, limiter);
1100 if (!hasWrapperElement) {
1101 if (mapping.Attribute != null) {
1103 throw new InvalidOperationException(Res.GetString(Res.XmlRpcLitAttributeAttributes));
1106 throw new InvalidOperationException(Res.GetString(Res.XmlInvalidAttributeType, "XmlAttribute"));
1110 if (rpc && xmlReflectionMembers[i].IsReturnValue) {
1111 if (i > 0) throw new InvalidOperationException(Res.GetString(Res.XmlInvalidReturnPosition));
1112 mapping.IsReturnValue = true;
1114 mappings[i] = mapping;
1115 isSequence |= mapping.IsSequence;
1116 if (!xmlReflectionMembers[i].XmlAttributes.XmlIgnore) {
1117 // add All memeber accessors to the scope accessors
1118 AddUniqueAccessor(mapping, elements, attributes, isSequence);
1121 mappings[i] = mapping;
1122 if (mapping.Text != null) {
1123 if (textAccessor != null) {
1124 throw new InvalidOperationException(Res.GetString(Res.XmlIllegalMultipleTextMembers));
1126 textAccessor = mapping.Text;
1129 if (mapping.Xmlns != null) {
1130 if (members.XmlnsMember != null)
1131 throw new InvalidOperationException(Res.GetString(Res.XmlMultipleXmlnsMembers));
1132 members.XmlnsMember = mapping;
1135 catch (Exception e) {
1136 if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException) {
1139 throw CreateReflectionException(xmlReflectionMembers[i].MemberName, e);
1143 throw new InvalidOperationException(Res.GetString(Res.XmlSequenceMembers, "Order"));
1145 members.Members = mappings;
1146 members.HasWrapperElement = hasWrapperElement;
1150 MemberMapping ImportMemberMapping(XmlReflectionMember xmlReflectionMember, string ns, XmlReflectionMember[] xmlReflectionMembers, bool rpc, bool openModel, RecursionLimiter limiter) {
1151 XmlSchemaForm form = rpc ? XmlSchemaForm.Unqualified : XmlSchemaForm.Qualified;
1152 XmlAttributes a = xmlReflectionMember.XmlAttributes;
1153 TypeDesc typeDesc = typeScope.GetTypeDesc(xmlReflectionMember.MemberType);
1155 if (a.XmlFlags == 0) {
1156 if (typeDesc.IsArrayLike) {
1157 XmlArrayAttribute xmlArray = CreateArrayAttribute(typeDesc);
1158 xmlArray.ElementName = xmlReflectionMember.MemberName;
1159 xmlArray.Namespace = rpc ? null : ns;
1160 xmlArray.Form = form;
1161 a.XmlArray = xmlArray;
1164 XmlElementAttribute xmlElement = CreateElementAttribute(typeDesc);
1165 // If there is no metadata specified on a parameter, then see if someone used
1166 // an XmlRoot attribute on the struct or class.
1167 if (typeDesc.IsStructLike) {
1168 XmlAttributes structAttrs = new XmlAttributes(xmlReflectionMember.MemberType);
1169 if (structAttrs.XmlRoot != null) {
1170 if (structAttrs.XmlRoot.ElementName.Length > 0)
1171 xmlElement.ElementName = structAttrs.XmlRoot.ElementName;
1173 xmlElement.Namespace = null;
1174 if (structAttrs.XmlRoot.IsNullableSpecified)
1175 xmlElement.IsNullable = structAttrs.XmlRoot.IsNullable;
1178 xmlElement.Namespace = structAttrs.XmlRoot.Namespace;
1179 xmlElement.IsNullable = structAttrs.XmlRoot.IsNullable;
1183 if (xmlElement.ElementName.Length == 0)
1184 xmlElement.ElementName = xmlReflectionMember.MemberName;
1185 if (xmlElement.Namespace == null && !rpc)
1186 xmlElement.Namespace = ns;
1187 xmlElement.Form = form;
1188 a.XmlElements.Add(xmlElement);
1191 else if (a.XmlRoot != null) {
1192 CheckNullable(a.XmlRoot.IsNullable, typeDesc, null);
1194 MemberMapping member = new MemberMapping();
1195 member.Name = xmlReflectionMember.MemberName;
1196 bool checkSpecified = FindSpecifiedMember(xmlReflectionMember.MemberName, xmlReflectionMembers) != null;
1197 FieldModel model = new FieldModel(xmlReflectionMember.MemberName, xmlReflectionMember.MemberType, typeScope.GetTypeDesc(xmlReflectionMember.MemberType), checkSpecified, false);
1198 member.CheckShouldPersist = model.CheckShouldPersist;
1199 member.CheckSpecified = model.CheckSpecified;
1200 member.ReadOnly = model.ReadOnly; // || !model.FieldTypeDesc.HasDefaultConstructor;
1202 Type choiceIdentifierType = null;
1203 if (a.XmlChoiceIdentifier != null) {
1204 choiceIdentifierType = GetChoiceIdentifierType(a.XmlChoiceIdentifier, xmlReflectionMembers, typeDesc.IsArrayLike, model.Name);
1206 ImportAccessorMapping(member, model, a, ns, choiceIdentifierType, rpc, openModel, limiter);
1207 if (xmlReflectionMember.OverrideIsNullable && member.Elements.Length > 0)
1208 member.Elements[0].IsNullable = false;
1212 internal static XmlReflectionMember FindSpecifiedMember(string memberName, XmlReflectionMember[] reflectionMembers) {
1213 for (int i = 0; i < reflectionMembers.Length; i++)
1214 if (string.Compare(reflectionMembers[i].MemberName, memberName + "Specified", StringComparison.Ordinal) == 0)
1215 return reflectionMembers[i];
1219 MemberMapping ImportFieldMapping(StructModel parent, FieldModel model, XmlAttributes a, string ns, RecursionLimiter limiter) {
1220 MemberMapping member = new MemberMapping();
1221 member.Name = model.Name;
1222 member.CheckShouldPersist = model.CheckShouldPersist;
1223 member.CheckSpecified = model.CheckSpecified;
1224 member.MemberInfo = model.MemberInfo;
1225 member.CheckSpecifiedMemberInfo = model.CheckSpecifiedMemberInfo;
1226 member.CheckShouldPersistMethodInfo = model.CheckShouldPersistMethodInfo;
1227 member.ReadOnly = model.ReadOnly; // || !model.FieldTypeDesc.HasDefaultConstructor;
1228 Type choiceIdentifierType = null;
1229 if (a.XmlChoiceIdentifier != null) {
1230 choiceIdentifierType = GetChoiceIdentifierType(a.XmlChoiceIdentifier, parent, model.FieldTypeDesc.IsArrayLike, model.Name);
1232 ImportAccessorMapping(member, model, a, ns, choiceIdentifierType, false, false, limiter);
1236 Type CheckChoiceIdentifierType(Type type, bool isArrayLike, string identifierName, string memberName) {
1239 // Inconsistent type of the choice identifier '{0}'. Please use {1}.
1240 throw new InvalidOperationException(Res.GetString(Res.XmlChoiceIdentifierType, identifierName, memberName, type.GetElementType().FullName));
1242 type = type.GetElementType();
1244 else if (isArrayLike) {
1245 // Inconsistent type of the choice identifier '{0}'. Please use {1}.
1246 throw new InvalidOperationException(Res.GetString(Res.XmlChoiceIdentifierArrayType, identifierName, memberName, type.FullName));
1250 // Choice identifier '{0}' must be an enum.
1251 throw new InvalidOperationException(Res.GetString(Res.XmlChoiceIdentifierTypeEnum, identifierName));
1256 Type GetChoiceIdentifierType(XmlChoiceIdentifierAttribute choice, XmlReflectionMember[] xmlReflectionMembers, bool isArrayLike, string accessorName) {
1257 for (int i = 0; i < xmlReflectionMembers.Length; i++) {
1258 if (choice.MemberName == xmlReflectionMembers[i].MemberName) {
1259 return CheckChoiceIdentifierType(xmlReflectionMembers[i].MemberType, isArrayLike, choice.MemberName, accessorName);
1262 // Missing '{0}' needed for serialization of choice '{1}'.
1263 throw new InvalidOperationException(Res.GetString(Res.XmlChoiceIdentiferMemberMissing, choice.MemberName, accessorName));
1266 Type GetChoiceIdentifierType(XmlChoiceIdentifierAttribute choice, StructModel structModel, bool isArrayLike, string accessorName) {
1267 // check that the choice field exists
1269 MemberInfo[] infos = structModel.Type.GetMember(choice.MemberName, BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);
1270 if (infos == null || infos.Length == 0) {
1271 // if we can not find the choice identifier between fields, check proerties
1272 PropertyInfo info = structModel.Type.GetProperty(choice.MemberName, BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);
1275 // Missing '{0}' needed for serialization of choice '{1}'.
1276 throw new InvalidOperationException(Res.GetString(Res.XmlChoiceIdentiferMemberMissing, choice.MemberName, accessorName));
1278 infos = new MemberInfo[] { info };
1280 else if (infos.Length > 1) {
1281 // Ambiguous choice identifer: there are several members named '{0}'.
1282 throw new InvalidOperationException(Res.GetString(Res.XmlChoiceIdentiferAmbiguous, choice.MemberName));
1285 FieldModel member = structModel.GetFieldModel(infos[0]);
1286 if (member == null) {
1287 // Missing '{0}' needed for serialization of choice '{1}'.
1288 throw new InvalidOperationException(Res.GetString(Res.XmlChoiceIdentiferMemberMissing, choice.MemberName, accessorName));
1290 choice.MemberInfo = member.MemberInfo;
1291 Type enumType = member.FieldType;
1292 enumType = CheckChoiceIdentifierType(enumType, isArrayLike, choice.MemberName, accessorName);
1296 void CreateArrayElementsFromAttributes(ArrayMapping arrayMapping, XmlArrayItemAttributes attributes, Type arrayElementType, string arrayElementNs, RecursionLimiter limiter) {
1297 NameTable arrayItemElements = new NameTable(); // xmlelementname + xmlns -> ElementAccessor
1299 for (int i = 0; attributes != null && i < attributes.Count; i++) {
1300 XmlArrayItemAttribute xmlArrayItem = attributes[i];
1301 if (xmlArrayItem.NestingLevel != arrayNestingLevel)
1303 Type targetType = xmlArrayItem.Type != null ? xmlArrayItem.Type : arrayElementType;
1304 TypeDesc targetTypeDesc = typeScope.GetTypeDesc(targetType);
1305 ElementAccessor arrayItemElement = new ElementAccessor();
1306 arrayItemElement.Namespace = xmlArrayItem.Namespace == null ? arrayElementNs : xmlArrayItem.Namespace;
1307 arrayItemElement.Mapping = ImportTypeMapping(modelScope.GetTypeModel(targetType), arrayItemElement.Namespace, ImportContext.Element, xmlArrayItem.DataType, null, limiter);
1308 arrayItemElement.Name = xmlArrayItem.ElementName.Length == 0 ? arrayItemElement.Mapping.DefaultElementName : XmlConvert.EncodeLocalName(xmlArrayItem.ElementName);
1309 arrayItemElement.IsNullable = xmlArrayItem.IsNullableSpecified ? xmlArrayItem.IsNullable : targetTypeDesc.IsNullable || targetTypeDesc.IsOptionalValue;
1310 arrayItemElement.Form = xmlArrayItem.Form == XmlSchemaForm.None ? XmlSchemaForm.Qualified : xmlArrayItem.Form;
1311 CheckForm(arrayItemElement.Form, arrayElementNs != arrayItemElement.Namespace);
1312 CheckNullable(arrayItemElement.IsNullable, targetTypeDesc, arrayItemElement.Mapping);
1313 AddUniqueAccessor(arrayItemElements, arrayItemElement);
1315 arrayMapping.Elements = (ElementAccessor[])arrayItemElements.ToArray(typeof(ElementAccessor));
1318 void ImportAccessorMapping(MemberMapping accessor, FieldModel model, XmlAttributes a, string ns, Type choiceIdentifierType, bool rpc, bool openModel, RecursionLimiter limiter) {
1319 XmlSchemaForm elementFormDefault = XmlSchemaForm.Qualified;
1320 int previousNestingLevel = arrayNestingLevel;
1321 int sequenceId = -1;
1322 XmlArrayItemAttributes previousArrayItemAttributes = savedArrayItemAttributes;
1323 string previousArrayNamespace = savedArrayNamespace;
1324 arrayNestingLevel = 0;
1325 savedArrayItemAttributes = null;
1326 savedArrayNamespace = null;
1327 Type accessorType = model.FieldType;
1328 string accessorName = model.Name;
1329 ArrayList elementList = new ArrayList();
1330 NameTable elements = new NameTable();
1331 accessor.TypeDesc = typeScope.GetTypeDesc(accessorType);
1332 XmlAttributeFlags flags = a.XmlFlags;
1333 accessor.Ignore = a.XmlIgnore;
1335 CheckTopLevelAttributes(a, accessorName);
1337 CheckAmbiguousChoice(a, accessorType, accessorName);
1339 XmlAttributeFlags elemFlags = XmlAttributeFlags.Elements | XmlAttributeFlags.Text | XmlAttributeFlags.AnyElements | XmlAttributeFlags.ChoiceIdentifier;
1340 XmlAttributeFlags attrFlags = XmlAttributeFlags.Attribute | XmlAttributeFlags.AnyAttribute;
1341 XmlAttributeFlags arrayFlags = XmlAttributeFlags.Array | XmlAttributeFlags.ArrayItems;
1343 // special case for byte[]. It can be a primitive (base64Binary or hexBinary), or it can
1344 // be an array of bytes. Our default is primitive; specify [XmlArray] to get array behavior.
1345 if ((flags & arrayFlags) != 0 && accessorType == typeof(byte[]))
1346 accessor.TypeDesc = typeScope.GetArrayTypeDesc(accessorType);
1348 if (a.XmlChoiceIdentifier != null) {
1349 accessor.ChoiceIdentifier = new ChoiceIdentifierAccessor();
1350 accessor.ChoiceIdentifier.MemberName = a.XmlChoiceIdentifier.MemberName;
1351 accessor.ChoiceIdentifier.MemberInfo = a.XmlChoiceIdentifier.MemberInfo;
1352 accessor.ChoiceIdentifier.Mapping = ImportTypeMapping(modelScope.GetTypeModel(choiceIdentifierType), ns, ImportContext.Element, String.Empty, null, limiter);
1353 CheckChoiceIdentifierMapping((EnumMapping)accessor.ChoiceIdentifier.Mapping);
1356 if (accessor.TypeDesc.IsArrayLike) {
1357 Type arrayElementType = TypeScope.GetArrayElementType(accessorType, model.FieldTypeDesc.FullName + "." + model.Name);
1359 if ((flags & attrFlags) != 0) {
1360 if ((flags & attrFlags) != flags)
1361 throw new InvalidOperationException(Res.GetString(Res.XmlIllegalAttributesArrayAttribute));
1363 if (a.XmlAttribute != null && !accessor.TypeDesc.ArrayElementTypeDesc.IsPrimitive && !accessor.TypeDesc.ArrayElementTypeDesc.IsEnum) {
1365 if (accessor.TypeDesc.ArrayElementTypeDesc.Kind == TypeKind.Serializable) {
1366 throw new InvalidOperationException(Res.GetString(Res.XmlIllegalAttrOrTextInterface, accessorName, accessor.TypeDesc.ArrayElementTypeDesc.FullName, typeof(IXmlSerializable).Name));
1369 throw new InvalidOperationException(Res.GetString(Res.XmlIllegalAttrOrText, accessorName, accessor.TypeDesc.ArrayElementTypeDesc.FullName));
1373 bool isList = a.XmlAttribute != null && (accessor.TypeDesc.ArrayElementTypeDesc.IsPrimitive || accessor.TypeDesc.ArrayElementTypeDesc.IsEnum);
1375 if (a.XmlAnyAttribute != null) {
1376 a.XmlAttribute = new XmlAttributeAttribute();
1379 AttributeAccessor attribute = new AttributeAccessor();
1380 Type targetType = a.XmlAttribute.Type == null ? arrayElementType : a.XmlAttribute.Type;
1381 TypeDesc targetTypeDesc = typeScope.GetTypeDesc(targetType);
1382 attribute.Name = Accessor.EscapeQName(a.XmlAttribute.AttributeName.Length == 0 ? accessorName : a.XmlAttribute.AttributeName);
1383 attribute.Namespace = a.XmlAttribute.Namespace == null ? ns : a.XmlAttribute.Namespace;
1384 attribute.Form = a.XmlAttribute.Form;
1385 if (attribute.Form == XmlSchemaForm.None && ns != attribute.Namespace) {
1386 attribute.Form = XmlSchemaForm.Qualified;
1388 attribute.CheckSpecial();
1389 CheckForm(attribute.Form, ns != attribute.Namespace);
1390 attribute.Mapping = ImportTypeMapping(modelScope.GetTypeModel(targetType), ns, ImportContext.Attribute, a.XmlAttribute.DataType, null, isList, false, limiter);
1391 attribute.IsList = isList;
1392 attribute.Default = GetDefaultValue(model.FieldTypeDesc, model.FieldType, a);
1393 attribute.Any = (a.XmlAnyAttribute != null);
1394 if (attribute.Form == XmlSchemaForm.Qualified && attribute.Namespace != ns) {
1395 if (xsdAttributes == null)
1396 xsdAttributes = new NameTable();
1397 attribute = (AttributeAccessor)ReconcileAccessor(attribute, xsdAttributes);
1399 accessor.Attribute = attribute;
1402 else if ((flags & elemFlags) != 0) {
1403 if ((flags & elemFlags) != flags)
1404 throw new InvalidOperationException(Res.GetString(Res.XmlIllegalElementsArrayAttribute));
1406 if (a.XmlText != null) {
1407 TextAccessor text = new TextAccessor();
1408 Type targetType = a.XmlText.Type == null ? arrayElementType : a.XmlText.Type;
1409 TypeDesc targetTypeDesc = typeScope.GetTypeDesc(targetType);
1410 text.Name = accessorName; // unused except to make more helpful error messages
1411 text.Mapping = ImportTypeMapping(modelScope.GetTypeModel(targetType), ns, ImportContext.Text, a.XmlText.DataType, null, true, false, limiter);
1412 if (!(text.Mapping is SpecialMapping) && targetTypeDesc != typeScope.GetTypeDesc(typeof(string)))
1413 throw new InvalidOperationException(Res.GetString(Res.XmlIllegalArrayTextAttribute, accessorName));
1415 accessor.Text = text;
1417 if (a.XmlText == null && a.XmlElements.Count == 0 && a.XmlAnyElements.Count == 0)
1418 a.XmlElements.Add(CreateElementAttribute(accessor.TypeDesc));
1420 for (int i = 0; i < a.XmlElements.Count; i++) {
1421 XmlElementAttribute xmlElement = a.XmlElements[i];
1422 Type targetType = xmlElement.Type == null ? arrayElementType : xmlElement.Type;
1423 TypeDesc targetTypeDesc = typeScope.GetTypeDesc(targetType);
1424 TypeModel typeModel = modelScope.GetTypeModel(targetType);
1425 ElementAccessor element = new ElementAccessor();
1426 element.Namespace = rpc ? null : xmlElement.Namespace == null ? ns : xmlElement.Namespace;
1427 element.Mapping = ImportTypeMapping(typeModel, rpc ? ns : element.Namespace, ImportContext.Element, xmlElement.DataType, null, limiter);
1428 if (a.XmlElements.Count == 1) {
1429 element.Name = XmlConvert.EncodeLocalName(xmlElement.ElementName.Length == 0 ? accessorName : xmlElement.ElementName);
1430 //element.IsUnbounded = element.Mapping is ArrayMapping;
1433 element.Name = xmlElement.ElementName.Length == 0 ? element.Mapping.DefaultElementName : XmlConvert.EncodeLocalName(xmlElement.ElementName);
1435 element.Default = GetDefaultValue(model.FieldTypeDesc, model.FieldType, a);
1436 if (xmlElement.IsNullableSpecified && !xmlElement.IsNullable && typeModel.TypeDesc.IsOptionalValue)
1437 //XmlInvalidNotNullable=IsNullable may not be set to 'false' for a Nullable<{0}> type. Consider using '{0}' type or removing the IsNullable property from the XmlElement attribute.
1438 throw new InvalidOperationException(Res.GetString(Res.XmlInvalidNotNullable, typeModel.TypeDesc.BaseTypeDesc.FullName, "XmlElement"));
1439 element.IsNullable = xmlElement.IsNullableSpecified ? xmlElement.IsNullable : typeModel.TypeDesc.IsOptionalValue;
1440 element.Form = rpc ? XmlSchemaForm.Unqualified : xmlElement.Form == XmlSchemaForm.None ? elementFormDefault : xmlElement.Form;
1442 CheckNullable(element.IsNullable, targetTypeDesc, element.Mapping);
1444 CheckForm(element.Form, ns != element.Namespace);
1445 element = ReconcileLocalAccessor(element, ns);
1447 if (xmlElement.Order != -1) {
1448 if (xmlElement.Order != sequenceId && sequenceId != -1)
1449 throw new InvalidOperationException(Res.GetString(Res.XmlSequenceMatch, "Order"));
1450 sequenceId = xmlElement.Order;
1452 AddUniqueAccessor(elements, element);
1453 elementList.Add(element);
1455 NameTable anys = new NameTable();
1456 for (int i = 0; i < a.XmlAnyElements.Count; i++) {
1457 XmlAnyElementAttribute xmlAnyElement = a.XmlAnyElements[i];
1458 Type targetType = typeof(IXmlSerializable).IsAssignableFrom(arrayElementType) ? arrayElementType : typeof(XmlNode).IsAssignableFrom(arrayElementType) ? arrayElementType : typeof(XmlElement);
1459 if (!arrayElementType.IsAssignableFrom(targetType))
1460 throw new InvalidOperationException(Res.GetString(Res.XmlIllegalAnyElement, arrayElementType.FullName));
1461 string anyName = xmlAnyElement.Name.Length == 0 ? xmlAnyElement.Name : XmlConvert.EncodeLocalName(xmlAnyElement.Name);
1462 string anyNs = xmlAnyElement.NamespaceSpecified ? xmlAnyElement.Namespace : null;
1463 if (anys[anyName, anyNs] != null) {
1464 // ignore duplicate anys
1467 anys[anyName, anyNs] = xmlAnyElement;
1468 if (elements[anyName, (anyNs == null ? ns : anyNs)] != null) {
1469 throw new InvalidOperationException(Res.GetString(Res.XmlAnyElementDuplicate, accessorName, xmlAnyElement.Name, xmlAnyElement.Namespace == null ? "null" : xmlAnyElement.Namespace));
1471 ElementAccessor element = new ElementAccessor();
1472 element.Name = anyName;
1473 element.Namespace = anyNs == null ? ns : anyNs;
1475 element.AnyNamespaces = anyNs;
1476 TypeDesc targetTypeDesc = typeScope.GetTypeDesc(targetType);
1477 TypeModel typeModel = modelScope.GetTypeModel(targetType);
1478 if (element.Name.Length > 0)
1479 typeModel.TypeDesc.IsMixed = true;
1480 element.Mapping = ImportTypeMapping(typeModel, element.Namespace, ImportContext.Element, String.Empty, null, limiter);
1481 element.Default = GetDefaultValue(model.FieldTypeDesc, model.FieldType, a);
1482 element.IsNullable = false;
1483 element.Form = elementFormDefault;
1485 CheckNullable(element.IsNullable, targetTypeDesc, element.Mapping);
1487 CheckForm(element.Form, ns != element.Namespace);
1488 element = ReconcileLocalAccessor(element, ns);
1490 elements.Add(element.Name, element.Namespace, element);
1491 elementList.Add(element);
1492 if (xmlAnyElement.Order != -1) {
1493 if (xmlAnyElement.Order != sequenceId && sequenceId != -1)
1494 throw new InvalidOperationException(Res.GetString(Res.XmlSequenceMatch, "Order"));
1495 sequenceId = xmlAnyElement.Order;
1500 if ((flags & arrayFlags) != 0) {
1501 if ((flags & arrayFlags) != flags)
1502 throw new InvalidOperationException(Res.GetString(Res.XmlIllegalArrayArrayAttribute));
1505 TypeDesc arrayElementTypeDesc = typeScope.GetTypeDesc(arrayElementType);
1506 if (a.XmlArray == null)
1507 a.XmlArray = CreateArrayAttribute(accessor.TypeDesc);
1508 if (CountAtLevel(a.XmlArrayItems, arrayNestingLevel) == 0)
1509 a.XmlArrayItems.Add(CreateArrayItemAttribute(arrayElementTypeDesc, arrayNestingLevel));
1510 ElementAccessor arrayElement = new ElementAccessor();
1511 arrayElement.Name = XmlConvert.EncodeLocalName(a.XmlArray.ElementName.Length == 0 ? accessorName : a.XmlArray.ElementName);
1512 arrayElement.Namespace = rpc ? null : a.XmlArray.Namespace == null ? ns : a.XmlArray.Namespace;
1513 savedArrayItemAttributes = a.XmlArrayItems;
1514 savedArrayNamespace = arrayElement.Namespace;
1515 ArrayMapping arrayMapping = ImportArrayLikeMapping(modelScope.GetArrayModel(accessorType), ns, limiter);
1516 arrayElement.Mapping = arrayMapping;
1517 arrayElement.IsNullable = a.XmlArray.IsNullable;
1518 arrayElement.Form = rpc ? XmlSchemaForm.Unqualified : a.XmlArray.Form == XmlSchemaForm.None ? elementFormDefault : a.XmlArray.Form;
1519 sequenceId = a.XmlArray.Order;
1520 CheckNullable(arrayElement.IsNullable, accessor.TypeDesc, arrayElement.Mapping);
1522 CheckForm(arrayElement.Form, ns != arrayElement.Namespace);
1523 arrayElement = ReconcileLocalAccessor(arrayElement, ns);
1525 savedArrayItemAttributes = null;
1526 savedArrayNamespace = null;
1528 AddUniqueAccessor(elements, arrayElement);
1529 elementList.Add(arrayElement);
1532 else if (!accessor.TypeDesc.IsVoid) {
1533 XmlAttributeFlags allFlags = XmlAttributeFlags.Elements | XmlAttributeFlags.Text | XmlAttributeFlags.Attribute | XmlAttributeFlags.AnyElements | XmlAttributeFlags.ChoiceIdentifier | XmlAttributeFlags.XmlnsDeclarations;
1534 if ((flags & allFlags) != flags)
1535 throw new InvalidOperationException(Res.GetString(Res.XmlIllegalAttribute));
1537 if (accessor.TypeDesc.IsPrimitive || accessor.TypeDesc.IsEnum) {
1538 if (a.XmlAnyElements.Count > 0) throw new InvalidOperationException(Res.GetString(Res.XmlIllegalAnyElement, accessor.TypeDesc.FullName));
1540 if (a.XmlAttribute != null) {
1541 if (a.XmlElements.Count > 0) throw new InvalidOperationException(Res.GetString(Res.XmlIllegalAttribute));
1542 if (a.XmlAttribute.Type != null) throw new InvalidOperationException(Res.GetString(Res.XmlIllegalType, "XmlAttribute"));
1543 AttributeAccessor attribute = new AttributeAccessor();
1544 attribute.Name = Accessor.EscapeQName(a.XmlAttribute.AttributeName.Length == 0 ? accessorName : a.XmlAttribute.AttributeName);
1545 attribute.Namespace = a.XmlAttribute.Namespace == null ? ns : a.XmlAttribute.Namespace;
1546 attribute.Form = a.XmlAttribute.Form;
1547 if (attribute.Form == XmlSchemaForm.None && ns != attribute.Namespace) {
1548 attribute.Form = XmlSchemaForm.Qualified;
1550 attribute.CheckSpecial();
1551 CheckForm(attribute.Form, ns != attribute.Namespace);
1552 attribute.Mapping = ImportTypeMapping(modelScope.GetTypeModel(accessorType), ns, ImportContext.Attribute, a.XmlAttribute.DataType, null, limiter);
1553 attribute.Default = GetDefaultValue(model.FieldTypeDesc, model.FieldType, a);
1554 attribute.Any = a.XmlAnyAttribute != null;
1555 if (attribute.Form == XmlSchemaForm.Qualified && attribute.Namespace != ns) {
1556 if (xsdAttributes == null)
1557 xsdAttributes = new NameTable();
1558 attribute = (AttributeAccessor)ReconcileAccessor(attribute, xsdAttributes);
1560 accessor.Attribute = attribute;
1563 if (a.XmlText != null) {
1564 if (a.XmlText.Type != null && a.XmlText.Type != accessorType)
1565 throw new InvalidOperationException(Res.GetString(Res.XmlIllegalType, "XmlText"));
1566 TextAccessor text = new TextAccessor();
1567 text.Name = accessorName; // unused except to make more helpful error messages
1568 text.Mapping = ImportTypeMapping(modelScope.GetTypeModel(accessorType), ns, ImportContext.Text, a.XmlText.DataType, null, limiter);
1569 accessor.Text = text;
1571 else if (a.XmlElements.Count == 0) {
1572 a.XmlElements.Add(CreateElementAttribute(accessor.TypeDesc));
1575 for (int i = 0; i < a.XmlElements.Count; i++) {
1576 XmlElementAttribute xmlElement = a.XmlElements[i];
1577 if (xmlElement.Type != null) {
1578 if (typeScope.GetTypeDesc(xmlElement.Type) != accessor.TypeDesc)
1579 throw new InvalidOperationException(Res.GetString(Res.XmlIllegalType, "XmlElement"));
1581 ElementAccessor element = new ElementAccessor();
1582 element.Name = XmlConvert.EncodeLocalName(xmlElement.ElementName.Length == 0 ? accessorName : xmlElement.ElementName);
1583 element.Namespace = rpc ? null : xmlElement.Namespace == null ? ns : xmlElement.Namespace;
1584 TypeModel typeModel = modelScope.GetTypeModel(accessorType);
1585 element.Mapping = ImportTypeMapping(typeModel, rpc ? ns : element.Namespace, ImportContext.Element, xmlElement.DataType, null, limiter);
1586 if (element.Mapping.TypeDesc.Kind == TypeKind.Node) {
1589 element.Default = GetDefaultValue(model.FieldTypeDesc, model.FieldType, a);
1590 if (xmlElement.IsNullableSpecified && !xmlElement.IsNullable && typeModel.TypeDesc.IsOptionalValue)
1591 //XmlInvalidNotNullable=IsNullable may not be set to 'false' for a Nullable<{0}> type. Consider using '{0}' type or removing the IsNullable property from the XmlElement attribute.
1592 throw new InvalidOperationException(Res.GetString(Res.XmlInvalidNotNullable, typeModel.TypeDesc.BaseTypeDesc.FullName, "XmlElement"));
1593 element.IsNullable = xmlElement.IsNullableSpecified ? xmlElement.IsNullable : typeModel.TypeDesc.IsOptionalValue;
1594 element.Form = rpc ? XmlSchemaForm.Unqualified : xmlElement.Form == XmlSchemaForm.None ? elementFormDefault : xmlElement.Form;
1596 CheckNullable(element.IsNullable, accessor.TypeDesc, element.Mapping);
1598 CheckForm(element.Form, ns != element.Namespace);
1599 element = ReconcileLocalAccessor(element, ns);
1601 if (xmlElement.Order != -1) {
1602 if (xmlElement.Order != sequenceId && sequenceId != -1)
1603 throw new InvalidOperationException(Res.GetString(Res.XmlSequenceMatch, "Order"));
1604 sequenceId = xmlElement.Order;
1606 AddUniqueAccessor(elements, element);
1607 elementList.Add(element);
1612 if (flags != XmlAttributeFlags.XmlnsDeclarations)
1613 throw new InvalidOperationException(Res.GetString(Res.XmlSoleXmlnsAttribute));
1615 if (accessorType != typeof(XmlSerializerNamespaces)) {
1616 throw new InvalidOperationException(Res.GetString(Res.XmlXmlnsInvalidType, accessorName, accessorType.FullName, typeof(XmlSerializerNamespaces).FullName));
1618 accessor.Xmlns = new XmlnsAccessor();
1619 accessor.Ignore = true;
1622 if (a.XmlAttribute != null || a.XmlText != null) {
1623 if (accessor.TypeDesc.Kind == TypeKind.Serializable) {
1624 throw new InvalidOperationException(Res.GetString(Res.XmlIllegalAttrOrTextInterface, accessorName, accessor.TypeDesc.FullName, typeof(IXmlSerializable).Name));
1627 throw new InvalidOperationException(Res.GetString(Res.XmlIllegalAttrOrText, accessorName, accessor.TypeDesc));
1630 if (a.XmlElements.Count == 0 && a.XmlAnyElements.Count == 0)
1631 a.XmlElements.Add(CreateElementAttribute(accessor.TypeDesc));
1632 for (int i = 0; i < a.XmlElements.Count; i++) {
1633 XmlElementAttribute xmlElement = a.XmlElements[i];
1634 Type targetType = xmlElement.Type == null ? accessorType : xmlElement.Type;
1635 TypeDesc targetTypeDesc = typeScope.GetTypeDesc(targetType);
1636 ElementAccessor element = new ElementAccessor();
1637 TypeModel typeModel = modelScope.GetTypeModel(targetType);
1638 element.Namespace = rpc ? null : xmlElement.Namespace == null ? ns : xmlElement.Namespace;
1639 element.Mapping = ImportTypeMapping(typeModel, rpc ? ns : element.Namespace, ImportContext.Element, xmlElement.DataType, null, false, openModel, limiter);
1640 if (a.XmlElements.Count == 1) {
1641 element.Name = XmlConvert.EncodeLocalName(xmlElement.ElementName.Length == 0 ? accessorName : xmlElement.ElementName);
1644 element.Name = xmlElement.ElementName.Length == 0 ? element.Mapping.DefaultElementName : XmlConvert.EncodeLocalName(xmlElement.ElementName);
1646 element.Default = GetDefaultValue(model.FieldTypeDesc, model.FieldType, a);
1647 if (xmlElement.IsNullableSpecified && !xmlElement.IsNullable && typeModel.TypeDesc.IsOptionalValue)
1648 //XmlInvalidNotNullable=IsNullable may not be set to 'false' for a Nullable<{0}> type. Consider using '{0}' type or removing the IsNullable property from the XmlElement attribute.
1649 throw new InvalidOperationException(Res.GetString(Res.XmlInvalidNotNullable, typeModel.TypeDesc.BaseTypeDesc.FullName, "XmlElement"));
1650 element.IsNullable = xmlElement.IsNullableSpecified ? xmlElement.IsNullable : typeModel.TypeDesc.IsOptionalValue;
1651 element.Form = rpc ? XmlSchemaForm.Unqualified : xmlElement.Form == XmlSchemaForm.None ? elementFormDefault : xmlElement.Form;
1652 CheckNullable(element.IsNullable, targetTypeDesc, element.Mapping);
1655 CheckForm(element.Form, ns != element.Namespace);
1656 element = ReconcileLocalAccessor(element, ns);
1658 if (xmlElement.Order != -1) {
1659 if (xmlElement.Order != sequenceId && sequenceId != -1)
1660 throw new InvalidOperationException(Res.GetString(Res.XmlSequenceMatch, "Order"));
1661 sequenceId = xmlElement.Order;
1663 AddUniqueAccessor(elements, element);
1664 elementList.Add(element);
1666 NameTable anys = new NameTable();
1667 for (int i = 0; i < a.XmlAnyElements.Count; i++)
1669 XmlAnyElementAttribute xmlAnyElement = a.XmlAnyElements[i];
1670 Type targetType = typeof(IXmlSerializable).IsAssignableFrom(accessorType) ? accessorType : typeof(XmlNode).IsAssignableFrom(accessorType) ? accessorType : typeof(XmlElement);
1671 if (!accessorType.IsAssignableFrom(targetType))
1672 throw new InvalidOperationException(Res.GetString(Res.XmlIllegalAnyElement, accessorType.FullName));
1674 string anyName = xmlAnyElement.Name.Length == 0 ? xmlAnyElement.Name : XmlConvert.EncodeLocalName(xmlAnyElement.Name);
1675 string anyNs = xmlAnyElement.NamespaceSpecified ? xmlAnyElement.Namespace : null;
1676 if (anys[anyName, anyNs] != null)
1678 // ignore duplicate anys
1681 anys[anyName, anyNs] = xmlAnyElement;
1682 if (elements[anyName, (anyNs == null ? ns : anyNs)] != null)
1684 throw new InvalidOperationException(Res.GetString(Res.XmlAnyElementDuplicate, accessorName, xmlAnyElement.Name, xmlAnyElement.Namespace == null ? "null" : xmlAnyElement.Namespace));
1686 ElementAccessor element = new ElementAccessor();
1687 element.Name = anyName;
1688 element.Namespace = anyNs == null ? ns : anyNs;
1690 element.AnyNamespaces = anyNs;
1691 TypeDesc targetTypeDesc = typeScope.GetTypeDesc(targetType);
1692 TypeModel typeModel = modelScope.GetTypeModel(targetType);
1694 if (element.Name.Length > 0)
1695 typeModel.TypeDesc.IsMixed = true;
1696 element.Mapping = ImportTypeMapping(typeModel, element.Namespace, ImportContext.Element, String.Empty, null, false, openModel, limiter);
1697 element.Default = GetDefaultValue(model.FieldTypeDesc, model.FieldType, a);
1698 element.IsNullable = false;
1699 element.Form = elementFormDefault;
1700 CheckNullable(element.IsNullable, targetTypeDesc, element.Mapping);
1702 CheckForm(element.Form, ns != element.Namespace);
1703 element = ReconcileLocalAccessor(element, ns);
1705 if (xmlAnyElement.Order != -1) {
1706 if (xmlAnyElement.Order != sequenceId && sequenceId != -1)
1707 throw new InvalidOperationException(Res.GetString(Res.XmlSequenceMatch, "Order"));
1708 sequenceId = xmlAnyElement.Order;
1710 elements.Add(element.Name, element.Namespace, element);
1711 elementList.Add(element);
1715 accessor.Elements = (ElementAccessor[])elementList.ToArray(typeof(ElementAccessor));
1716 accessor.SequenceId = sequenceId;
1720 if (accessor.TypeDesc.IsArrayLike && accessor.Elements.Length > 0 && !(accessor.Elements[0].Mapping is ArrayMapping))
1721 throw new InvalidOperationException(Res.GetString(Res.XmlRpcLitArrayElement, accessor.Elements[0].Name));
1723 if (accessor.Xmlns != null)
1724 throw new InvalidOperationException(Res.GetString(Res.XmlRpcLitXmlns, accessor.Name));
1727 if (accessor.ChoiceIdentifier != null) {
1728 // find the enum value corresponding to each element
1729 accessor.ChoiceIdentifier.MemberIds = new string[accessor.Elements.Length];
1730 for (int i = 0; i < accessor.Elements.Length; i++) {
1732 ElementAccessor element = accessor.Elements[i];
1733 EnumMapping choiceMapping = (EnumMapping)accessor.ChoiceIdentifier.Mapping;
1734 for (int j = 0; j < choiceMapping.Constants.Length; j++) {
1735 string xmlName = choiceMapping.Constants[j].XmlName;
1737 if (element.Any && element.Name.Length == 0) {
1738 string anyNs = element.AnyNamespaces == null ? "##any" : element.AnyNamespaces;
1739 if (xmlName.Substring(0, xmlName.Length-1) == anyNs) {
1740 accessor.ChoiceIdentifier.MemberIds[i] = choiceMapping.Constants[j].Name;
1746 int colon = xmlName.LastIndexOf(':');
1747 string choiceNs = colon < 0 ? choiceMapping.Namespace : xmlName.Substring(0, colon);
1748 string choiceName = colon < 0 ? xmlName : xmlName.Substring(colon+1);
1750 if (element.Name == choiceName) {
1751 if ((element.Form == XmlSchemaForm.Unqualified && string.IsNullOrEmpty(choiceNs)) || element.Namespace == choiceNs) {
1752 accessor.ChoiceIdentifier.MemberIds[i] = choiceMapping.Constants[j].Name;
1759 if (element.Any && element.Name.Length == 0) {
1760 // Type {0} is missing enumeration value '##any' for XmlAnyElementAttribute.
1761 throw new InvalidOperationException(Res.GetString(Res.XmlChoiceMissingAnyValue, accessor.ChoiceIdentifier.Mapping.TypeDesc.FullName));
1764 string id = element.Namespace != null && element.Namespace.Length > 0 ? element.Namespace + ":" + element.Name : element.Name;
1765 // Type {0} is missing value for '{1}'.
1766 throw new InvalidOperationException(Res.GetString(Res.XmlChoiceMissingValue, accessor.ChoiceIdentifier.Mapping.TypeDesc.FullName, id, element.Name, element.Namespace));
1771 arrayNestingLevel = previousNestingLevel;
1772 savedArrayItemAttributes = previousArrayItemAttributes;
1773 savedArrayNamespace = previousArrayNamespace;
1777 void CheckTopLevelAttributes(XmlAttributes a, string accessorName) {
1778 XmlAttributeFlags flags = a.XmlFlags;
1780 if ((flags & (XmlAttributeFlags.Attribute | XmlAttributeFlags.AnyAttribute)) != 0)
1781 throw new InvalidOperationException(Res.GetString(Res.XmlRpcLitAttributeAttributes));
1783 if ((flags & (XmlAttributeFlags.Text | XmlAttributeFlags.AnyElements | XmlAttributeFlags.ChoiceIdentifier)) != 0)
1784 throw new InvalidOperationException(Res.GetString(Res.XmlRpcLitAttributes));
1786 if (a.XmlElements != null && a.XmlElements.Count > 0) {
1787 if (a.XmlElements.Count > 1) {
1788 throw new InvalidOperationException(Res.GetString(Res.XmlRpcLitElements));
1790 XmlElementAttribute xmlElement = a.XmlElements[0];
1791 if (xmlElement.Namespace != null) {
1792 throw new InvalidOperationException(Res.GetString(Res.XmlRpcLitElementNamespace, "Namespace", xmlElement.Namespace));
1794 if (xmlElement.IsNullable) {
1795 throw new InvalidOperationException(Res.GetString(Res.XmlRpcLitElementNullable, "IsNullable", "true"));
1798 if (a.XmlArray != null && a.XmlArray.Namespace != null) {
1799 throw new InvalidOperationException(Res.GetString(Res.XmlRpcLitElementNamespace, "Namespace", a.XmlArray.Namespace));
1803 void CheckAmbiguousChoice(XmlAttributes a, Type accessorType, string accessorName) {
1804 Hashtable choiceTypes = new Hashtable();
1806 XmlElementAttributes elements = a.XmlElements;
1807 if (elements != null && elements.Count >= 2 && a.XmlChoiceIdentifier == null) {
1808 for (int i = 0; i < elements.Count; i++) {
1809 Type type = elements[i].Type == null ? accessorType : elements[i].Type;
1810 if (choiceTypes.Contains(type)) {
1811 // You need to add {0} to the '{1}'.
1812 throw new InvalidOperationException(Res.GetString(Res.XmlChoiceIdentiferMissing, typeof(XmlChoiceIdentifierAttribute).Name, accessorName));
1815 choiceTypes.Add(type, false);
1819 if (choiceTypes.Contains(typeof(XmlElement)) && a.XmlAnyElements.Count > 0) {
1820 // You need to add {0} to the '{1}'.
1821 throw new InvalidOperationException(Res.GetString(Res.XmlChoiceIdentiferMissing, typeof(XmlChoiceIdentifierAttribute).Name, accessorName));
1824 XmlArrayItemAttributes items = a.XmlArrayItems;
1825 if (items != null && items.Count >= 2) {
1826 NameTable arrayTypes = new NameTable();
1828 for (int i = 0; i < items.Count; i++) {
1829 Type type = items[i].Type == null ? accessorType : items[i].Type;
1830 string ns = items[i].NestingLevel.ToString(CultureInfo.InvariantCulture);
1831 XmlArrayItemAttribute item = (XmlArrayItemAttribute)arrayTypes[type.FullName, ns];
1833 throw new InvalidOperationException(Res.GetString(Res.XmlArrayItemAmbiguousTypes, accessorName, item.ElementName, items[i].ElementName, typeof(XmlElementAttribute).Name, typeof(XmlChoiceIdentifierAttribute).Name, accessorName));
1836 arrayTypes[type.FullName, ns] = items[i];
1842 void CheckChoiceIdentifierMapping(EnumMapping choiceMapping) {
1843 NameTable ids = new NameTable();
1844 for (int i = 0; i < choiceMapping.Constants.Length; i++) {
1845 string choiceId = choiceMapping.Constants[i].XmlName;
1846 int colon = choiceId.LastIndexOf(':');
1847 string choiceName = colon < 0 ? choiceId : choiceId.Substring(colon+1);
1848 string choiceNs = colon < 0 ? "" : choiceId.Substring(0, colon);
1850 if (ids[choiceName, choiceNs] != null) {
1851 // Enum values in the XmlChoiceIdentifier '{0}' have to be unique. Value '{1}' already present.
1852 throw new InvalidOperationException(Res.GetString(Res.XmlChoiceIdDuplicate, choiceMapping.TypeName, choiceId));
1854 ids.Add(choiceName, choiceNs, choiceMapping.Constants[i]);
1858 object GetDefaultValue(TypeDesc fieldTypeDesc, Type t, XmlAttributes a) {
1859 if (a.XmlDefaultValue == null || a.XmlDefaultValue == DBNull.Value) return null;
1860 if (!(fieldTypeDesc.Kind == TypeKind.Primitive || fieldTypeDesc.Kind == TypeKind.Enum)) {
1861 //throw new InvalidOperationException(Res.GetString(Res.XmlIllegalDefault));
1862 a.XmlDefaultValue = null;
1863 return a.XmlDefaultValue;
1865 // for enums validate and return a string representation
1866 if (fieldTypeDesc.Kind == TypeKind.Enum) {
1867 string strValue = Enum.Format(t, a.XmlDefaultValue, "G").Replace(",", " ");
1868 string numValue = Enum.Format(t, a.XmlDefaultValue, "D");
1869 if (strValue == numValue) // means enum value wasn't recognized
1870 throw new InvalidOperationException(Res.GetString(Res.XmlInvalidDefaultValue, strValue, a.XmlDefaultValue.GetType().FullName));
1873 return a.XmlDefaultValue;
1876 static XmlArrayItemAttribute CreateArrayItemAttribute(TypeDesc typeDesc, int nestingLevel) {
1877 XmlArrayItemAttribute xmlArrayItem = new XmlArrayItemAttribute();
1878 xmlArrayItem.NestingLevel = nestingLevel;
1879 return xmlArrayItem;
1882 static XmlArrayAttribute CreateArrayAttribute(TypeDesc typeDesc) {
1883 XmlArrayAttribute xmlArrayItem = new XmlArrayAttribute();
1884 return xmlArrayItem;
1887 static XmlElementAttribute CreateElementAttribute(TypeDesc typeDesc) {
1888 XmlElementAttribute xmlElement = new XmlElementAttribute();
1889 xmlElement.IsNullable = typeDesc.IsOptionalValue;
1893 static void AddUniqueAccessor(INameScope scope, Accessor accessor) {
1894 Accessor existing = (Accessor)scope[accessor.Name, accessor.Namespace];
1895 if (existing != null) {
1896 if (accessor is ElementAccessor) {
1897 throw new InvalidOperationException(Res.GetString(Res.XmlDuplicateElementName, existing.Name, existing.Namespace));
1901 if (!(accessor is AttributeAccessor))
1902 throw new InvalidOperationException(Res.GetString(Res.XmlInternalErrorDetails, "Bad accessor type " + accessor.GetType().FullName));
1904 throw new InvalidOperationException(Res.GetString(Res.XmlDuplicateAttributeName, existing.Name, existing.Namespace));
1908 scope[accessor.Name, accessor.Namespace] = accessor;
1912 static void AddUniqueAccessor(MemberMapping member, INameScope elements, INameScope attributes, bool isSequence) {
1913 if (member.Attribute != null) {
1914 AddUniqueAccessor(attributes, member.Attribute);
1916 else if (!isSequence && member.Elements != null && member.Elements.Length > 0) {
1917 for (int i = 0; i < member.Elements.Length; i++) {
1918 AddUniqueAccessor(elements, member.Elements[i]);
1923 static void CheckForm(XmlSchemaForm form, bool isQualified) {
1924 if (isQualified && form == XmlSchemaForm.Unqualified) throw new InvalidOperationException(Res.GetString(Res.XmlInvalidFormUnqualified));
1927 static void CheckNullable(bool isNullable, TypeDesc typeDesc, TypeMapping mapping) {
1928 if (mapping is NullableMapping) return;
1929 if (mapping is SerializableMapping) return;
1930 if (isNullable && !typeDesc.IsNullable) throw new InvalidOperationException(Res.GetString(Res.XmlInvalidIsNullable, typeDesc.FullName));
1933 static ElementAccessor CreateElementAccessor(TypeMapping mapping, string ns) {
1934 ElementAccessor element = new ElementAccessor();
1935 bool isAny = mapping.TypeDesc.Kind == TypeKind.Node;
1936 if (!isAny && mapping is SerializableMapping) {
1937 isAny = ((SerializableMapping)mapping).IsAny;
1943 element.Name = mapping.DefaultElementName;
1944 element.Namespace = ns;
1946 element.Mapping = mapping;
1950 // will create a shallow type mapping for a top-level type
1951 internal static XmlTypeMapping GetTopLevelMapping(Type type, string defaultNamespace) {
1952 XmlAttributes a = new XmlAttributes(type);
1953 TypeDesc typeDesc = new TypeScope().GetTypeDesc(type);
1954 ElementAccessor element = new ElementAccessor();
1956 if (typeDesc.Kind == TypeKind.Node) {
1960 string ns = a.XmlRoot == null ? defaultNamespace : a.XmlRoot.Namespace;
1961 string typeName = string.Empty;
1962 if (a.XmlType != null)
1963 typeName = a.XmlType.TypeName;
1964 if (typeName.Length == 0)
1965 typeName = type.Name;
1967 element.Name = XmlConvert.EncodeLocalName(typeName);
1968 element.Namespace = ns;
1970 XmlTypeMapping mapping = new XmlTypeMapping(null, element);
1971 mapping.SetKeyInternal(XmlMapping.GenerateKey(type, a.XmlRoot, defaultNamespace));
1975 internal class ImportStructWorkItem {
1977 StructMapping mapping;
1979 internal ImportStructWorkItem(StructModel model, StructMapping mapping) {
1981 this.mapping = mapping;
1984 internal StructModel Model { get { return model; } }
1985 internal StructMapping Mapping { get { return mapping; } }
1988 internal class WorkItems {
1989 ArrayList list = new ArrayList();
1991 internal ImportStructWorkItem this[int index] {
1993 return (ImportStructWorkItem)list[index];
1996 list[index] = value;
2000 internal int Count {
2006 internal void Add(ImportStructWorkItem item) {
2010 internal bool Contains(StructMapping mapping) {
2011 return IndexOf(mapping) >= 0;
2014 internal int IndexOf(StructMapping mapping) {
2015 for (int i = 0; i < Count; i++) {
2016 if (this[i].Mapping == mapping)
2022 internal void RemoveAt(int index) {
2023 list.RemoveAt(index);
2027 internal class RecursionLimiter {
2030 WorkItems deferredWorkItems;
2032 internal RecursionLimiter() {
2034 this.maxDepth = DiagnosticsSwitches.NonRecursiveTypeLoading.Enabled ? 1 : int.MaxValue;
2037 internal bool IsExceededLimit { get { return this.depth > this.maxDepth; } }
2038 internal int Depth { get { return this.depth; } set { this.depth = value; } }
2040 internal WorkItems DeferredWorkItems {
2042 if (deferredWorkItems == null) {
2043 deferredWorkItems = new WorkItems();
2045 return deferredWorkItems;