[S.R.Serialization] implement XmlFormatReaderGenerator interpreter.
[mono.git] / mcs / class / System.Runtime.Serialization / ReferenceSources / XmlFormatReaderGenerator_static.cs
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Reflection;
5 using System.Xml;
6
7 namespace System.Runtime.Serialization
8 {
9         internal partial class XmlFormatReaderGenerator
10         {
11                 partial class CriticalHelper
12                 {
13                         internal XmlFormatClassReaderDelegate GenerateClassReader(ClassDataContract classContract)
14                         {
15                                 return (XmlReaderDelegator xr, XmlObjectSerializerReadContext ctx, XmlDictionaryString [] memberNames, XmlDictionaryString [] memberNamespaces) => new XmlFormatReaderInterpreter (classContract).ReadFromXml (xr, ctx, memberNames, memberNamespaces);
16                         }
17
18                         internal XmlFormatCollectionReaderDelegate GenerateCollectionReader(CollectionDataContract collectionContract)
19                         {
20                                 return (XmlReaderDelegator xr, XmlObjectSerializerReadContext ctx, XmlDictionaryString inm, XmlDictionaryString ins, CollectionDataContract cc) => new XmlFormatReaderInterpreter (collectionContract, false).ReadCollectionFromXml (xr, ctx, inm, ins, cc);
21                         }
22                         
23                         internal XmlFormatGetOnlyCollectionReaderDelegate GenerateGetOnlyCollectionReader(CollectionDataContract collectionContract)
24                         {
25                                 return (XmlReaderDelegator xr, XmlObjectSerializerReadContext ctx, XmlDictionaryString inm, XmlDictionaryString ins, CollectionDataContract cc) => new XmlFormatReaderInterpreter (collectionContract, true).ReadGetOnlyCollectionFromXml (xr, ctx, inm, ins, cc);
26                         }
27                 }
28         }
29
30         class XmlFormatReaderInterpreter
31         {
32                 public XmlFormatReaderInterpreter (ClassDataContract classContract)
33                 {
34                         this.classContract = classContract;
35                 }
36
37                 public XmlFormatReaderInterpreter (CollectionDataContract collectionContract, bool isGetOnly)
38                 {
39                         this.collectionContract = collectionContract;
40                         this.is_get_only_collection = isGetOnly;
41                 }
42
43                 bool is_get_only_collection;
44
45                 ClassDataContract classContract;
46
47                 CollectionDataContract collectionContract;
48
49                 object objectLocal;
50                 Type objectType;
51                 XmlReaderDelegator xmlReader;
52                 XmlObjectSerializerReadContext context;
53
54                 XmlDictionaryString [] memberNames = null;
55                 XmlDictionaryString [] memberNamespaces = null;
56                 XmlDictionaryString itemName = null;
57                 XmlDictionaryString itemNamespace = null;
58
59                 public object ReadFromXml (XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context, XmlDictionaryString[] memberNames, XmlDictionaryString[] memberNamespaces)
60                 {
61                         // InitArgs()
62                         this.xmlReader = xmlReader;
63                         this.context = context;
64                         this.memberNames = memberNames;
65                         this.memberNamespaces = memberNamespaces;
66                         
67                         //DemandSerializationFormatterPermission(classContract);
68                         //DemandMemberAccessPermission(memberAccessFlag);
69                         CreateObject (classContract);
70                         
71                         context.AddNewObject (objectLocal);
72                         InvokeOnDeserializing (classContract);
73             
74             string objectId = null;
75             
76                         if (HasFactoryMethod (classContract))
77                                 objectId = context.GetObjectId ();
78                         if (classContract.IsISerializable)
79                                 ReadISerializable (classContract);
80                         else
81                                 ReadClass (classContract);
82                         bool isFactoryType = InvokeFactoryMethod (classContract, objectId);
83                         if (Globals.TypeOfIDeserializationCallback.IsAssignableFrom (classContract.UnderlyingType))
84                                 ((IDeserializationCallback) objectLocal).OnDeserialization (null);
85                         InvokeOnDeserialized(classContract);
86                         if (objectId == null || !isFactoryType) {
87
88                                 // Do a conversion back from DateTimeOffsetAdapter to DateTimeOffset after deserialization.
89                                 // DateTimeOffsetAdapter is used here for deserialization purposes to bypass the ISerializable implementation
90                                 // on DateTimeOffset; which does not work in partial trust.
91
92                                 if (classContract.UnderlyingType == Globals.TypeOfDateTimeOffsetAdapter)
93                                         objectLocal = DateTimeOffsetAdapter.GetDateTimeOffset ((DateTimeOffsetAdapter) objectLocal);
94                                 // else - do we have to call CodeInterpreter.ConvertValue()? I guess not...
95                         }
96                         return objectLocal;
97                 }
98                 
99                 public object ReadCollectionFromXml (XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context, XmlDictionaryString itemName, XmlDictionaryString itemNamespace, CollectionDataContract collectionContract)
100                 {
101                         #region GenerateCollectionReaderHelper
102                         // InitArgs()
103                         this.xmlReader = xmlReader;
104                         this.context = context;
105                         this.itemName = itemName;
106                         this.itemNamespace = itemNamespace;
107
108                         this.collectionContract = collectionContract;
109
110                         #endregion
111
112                         ReadCollection (collectionContract);
113
114                         return objectLocal;
115                 }
116                 
117                 public void ReadGetOnlyCollectionFromXml (XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context, XmlDictionaryString itemName, XmlDictionaryString itemNamespace, CollectionDataContract collectionContract)
118                 {
119                         #region GenerateCollectionReaderHelper
120                         // InitArgs()
121                         this.xmlReader = xmlReader;
122                         this.context = context;
123                         this.itemName = itemName;
124                         this.itemNamespace = itemNamespace;
125
126                         this.collectionContract = collectionContract;
127
128                         #endregion
129
130                         ReadGetOnlyCollection (collectionContract);
131                 }
132
133                 void CreateObject (ClassDataContract classContract)
134                 {
135                         Type type = objectType = classContract.UnderlyingType;
136                         if (type.IsValueType && !classContract.IsNonAttributedType)
137                                 type = Globals.TypeOfValueType;
138
139                         if (classContract.UnderlyingType == Globals.TypeOfDBNull)
140                                 objectLocal = DBNull.Value;
141                         else if (classContract.IsNonAttributedType) {
142                                 if (type.IsValueType)
143                                         objectLocal = FormatterServices.GetUninitializedObject (type);
144                                 else
145                                         objectLocal = classContract.GetNonAttributedTypeConstructor ().Invoke (new object [0]);
146                         }
147                         else
148                                 objectLocal = XmlFormatReaderGenerator.UnsafeGetUninitializedObject (DataContract.GetIdForInitialization (classContract));
149                 }
150
151                 void InvokeOnDeserializing (ClassDataContract classContract)
152                 {
153                         if (classContract.BaseContract != null)
154                                 InvokeOnDeserializing (classContract.BaseContract);
155                         if (classContract.OnDeserializing != null)
156                                 classContract.OnDeserializing.Invoke (objectLocal, new object [] {context.GetStreamingContext ()});
157                 }
158
159                 void InvokeOnDeserialized (ClassDataContract classContract)
160                 {
161                         if (classContract.BaseContract != null)
162                                 InvokeOnDeserialized (classContract.BaseContract);
163                         if (classContract.OnDeserialized != null)
164                                 classContract.OnDeserialized.Invoke (objectLocal, new object [] {context.GetStreamingContext ()});
165                 }
166
167                 bool HasFactoryMethod (ClassDataContract classContract)
168                 {
169                         return Globals.TypeOfIObjectReference.IsAssignableFrom (classContract.UnderlyingType);
170                 }
171
172                 bool InvokeFactoryMethod (ClassDataContract classContract, string objectId)
173                 {
174                         if (HasFactoryMethod (classContract)) {
175                                 objectLocal = context.GetRealObject ((IObjectReference) objectLocal, objectId);
176                                 return true;
177                         }
178                         return false;
179                 }
180
181                 void ReadISerializable (ClassDataContract classContract)
182                 {
183                         ConstructorInfo ctor = classContract.GetISerializableConstructor ();
184                         context.ReadSerializationInfo (xmlReader, classContract.UnderlyingType);
185                         ctor.Invoke (objectLocal, new object [] {context.GetStreamingContext ()});
186                 }
187
188                 void ReadClass (ClassDataContract classContract)
189                 {
190                         if (classContract.HasExtensionData) {
191                                 ExtensionDataObject extensionData = new ExtensionDataObject ();
192                                 ReadMembers (classContract, extensionData);
193                                 ClassDataContract currentContract = classContract;
194                                 while (currentContract != null) {
195                                         MethodInfo extensionDataSetMethod = currentContract.ExtensionDataSetMethod;
196                                         if (extensionDataSetMethod != null)
197                                                 extensionDataSetMethod.Invoke (objectLocal, new object [] {extensionData});
198                                         currentContract = currentContract.BaseContract;
199                                 }
200                         }
201                         else
202                                 ReadMembers (classContract, null);
203                 }
204
205                 void ReadMembers (ClassDataContract classContract, ExtensionDataObject  extensionData)
206                 {
207                         int memberCount = classContract.MemberNames.Length;
208                         context.IncrementItemCount (memberCount);
209
210                         int memberIndex = -1;
211                         
212                         int firstRequiredMember;
213                         bool[] requiredMembers = GetRequiredMembers (classContract, out firstRequiredMember);
214                         bool hasRequiredMembers = (firstRequiredMember < memberCount);
215                         // FIXME: here I converted null as -1 but that may be wrong.
216                         int requiredIndex = hasRequiredMembers ? firstRequiredMember : -1;
217
218                         while (XmlObjectSerializerReadContext.MoveToNextElement (xmlReader)) {
219                                 int idx; // used as in "switch (idx)" in the original source.
220                                 if (hasRequiredMembers)
221                                         idx = context.GetMemberIndexWithRequiredMembers (xmlReader, memberNames, memberNamespaces, memberIndex, (int) requiredIndex, extensionData);
222                                 else
223                                         idx = context.GetMemberIndex (xmlReader, memberNames, memberNamespaces, memberIndex, extensionData);
224
225                                 if (memberCount > 0)
226                                         ReadMembers (idx, classContract, requiredMembers, ref memberIndex, ref requiredIndex);
227                         }
228
229                         if (hasRequiredMembers)
230                         {
231                                 if (requiredIndex < memberCount)
232                                         XmlObjectSerializerReadContext.ThrowRequiredMemberMissingException (xmlReader, memberIndex, requiredIndex, memberNames);
233                         }
234                 }
235
236                 int ReadMembers (int index, ClassDataContract classContract, bool [] requiredMembers, ref int memberIndex, ref int requiredIndex)
237                 {
238                         int memberCount = (classContract.BaseContract == null) ? 0 : ReadMembers (index, classContract.BaseContract, requiredMembers,
239                         ref memberIndex, ref requiredIndex);
240                         
241                         if (memberCount <= index && index < memberCount + classContract.Members.Count) {
242                                 DataMember dataMember = classContract.Members [index];
243                                 Type memberType = dataMember.MemberType;
244                                 if (dataMember.IsRequired) {
245                                         int nextRequiredIndex = memberCount + 1;
246                                         for (; nextRequiredIndex < requiredMembers.Length; nextRequiredIndex++)
247                                         if (requiredMembers [nextRequiredIndex])
248                                                 break;
249                                         requiredIndex = nextRequiredIndex;
250                                 }
251
252                                 if (dataMember.IsGetOnlyCollection) {
253                                         var value = CodeInterpreter.GetMember (dataMember.MemberInfo, objectLocal);
254                                         context.StoreCollectionMemberInfo (value);
255                                         ReadValue (memberType, dataMember.Name, classContract.StableName.Namespace);
256                                 } else {
257                                         var value = ReadValue (memberType, dataMember.Name, classContract.StableName.Namespace);
258                                         CodeInterpreter.SetMember (dataMember.MemberInfo, objectLocal, value);
259                                 }
260                                 memberIndex = index;
261                         }
262                         return memberCount + classContract.Members.Count;
263                 }
264
265                 bool[] GetRequiredMembers (ClassDataContract contract, out int firstRequiredMember)
266                 {
267                         int memberCount = contract.MemberNames.Length;
268                         bool [] requiredMembers = new bool [memberCount];
269                         GetRequiredMembers (contract, requiredMembers);
270                         for (firstRequiredMember = 0; firstRequiredMember < memberCount; firstRequiredMember++)
271                                 if (requiredMembers [firstRequiredMember])
272                                         break;
273                         return requiredMembers;
274                 }
275
276                 int GetRequiredMembers (ClassDataContract contract, bool[] requiredMembers)
277                 {
278                         int memberCount = (contract.BaseContract == null) ? 0 : GetRequiredMembers (contract.BaseContract, requiredMembers);
279                         List<DataMember> members = contract.Members;
280                         for (int i = 0; i < members.Count; i++, memberCount++)
281                                 requiredMembers [memberCount] = members [i].IsRequired;
282                         return memberCount;
283                 }
284
285                 object ReadValue (Type type, string name, string ns)
286                 {
287                         var valueType = type;
288                         object value = null;
289                         bool shouldAssignNullableValue = false;
290                         int nullables = 0;
291                         while (type.IsGenericType && type.GetGenericTypeDefinition () == Globals.TypeOfNullable) {
292                                 nullables++;
293                                 type = type.GetGenericArguments () [0];
294                         }
295                         
296                         PrimitiveDataContract primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract (type);
297                         if ((primitiveContract != null && primitiveContract.UnderlyingType != Globals.TypeOfObject) || nullables != 0 || type.IsValueType) {
298                                 context.ReadAttributes (xmlReader);
299                                 string objectId = context.ReadIfNullOrRef (xmlReader, type, DataContract.IsTypeSerializable (type));
300                                 // Deserialize null
301                 if (objectId == Globals.NullObjectId) {
302                                         
303                                         if (nullables != 0)
304                                                 value = FormatterServices.GetUninitializedObject (valueType);
305                                         else if (type.IsValueType)
306                                                 throw new SerializationException (SR.GetString (SR.ValueTypeCannotBeNull, DataContract.GetClrTypeFullName (type)));
307                                         else
308                                                 value = null;
309                                 } else if (objectId == string.Empty) {
310                                         // Deserialize value
311
312                                         // Compare against Globals.NewObjectId, which is set to string.Empty
313                                         
314                                         objectId = context.GetObjectId ();
315                                         
316                                         if (type.IsValueType) {
317                                                 if (!string.IsNullOrEmpty (objectId))
318                                                         throw new SerializationException (SR.GetString (SR.ValueTypeCannotHaveId, DataContract.GetClrTypeFullName(type)));
319                                         }
320                                         object innerValueRead = null;
321                                         if (nullables != 0)
322                                                 shouldAssignNullableValue = true;
323
324                                         if (primitiveContract != null && primitiveContract.UnderlyingType != Globals.TypeOfObject) {
325                                                 value = primitiveContract.XmlFormatReaderMethod.Invoke (xmlReader, new object [0]);
326                                                 if (!type.IsValueType)
327                                                         context.AddNewObject (value);
328                                         }
329                                         else
330                                                         value = InternalDeserialize (value, type, name, ns);
331                                 } else {
332                                         // Deserialize ref
333                                         if (type.IsValueType)
334                                                 throw new SerializationException (SR.GetString (SR.ValueTypeCannotHaveRef, DataContract.GetClrTypeFullName (type)));
335                                         else
336                                                 value = context.GetExistingObject (objectId, type, name, ns);
337                                 }
338
339                                 if (shouldAssignNullableValue) {
340                                         if (objectId != Globals.NullObjectId)
341                                                 value = WrapNullableObject (type, value, valueType, nullables);
342                                 }
343                         }
344                         else
345                                 value = InternalDeserialize (value, type, name, ns);
346
347                         return value;
348                 }
349
350                 object InternalDeserialize (object value, Type type, string name, string ns)
351                 {
352                         Type declaredType = type.IsPointer ? Globals.TypeOfReflectionPointer : type;
353                         var obj = context.InternalDeserialize (xmlReader, DataContract.GetId (declaredType.TypeHandle), declaredType.TypeHandle, name, ns);
354
355                         if (type.IsPointer)
356                                 // wow, there is no way to convert void* to object...
357                                 return XmlFormatGeneratorStatics.UnboxPointer.Invoke (null, new object [] {obj});
358                         else
359                                 return obj;
360                 }
361
362                 object WrapNullableObject (Type innerType, object innerValue, Type outerType, int nullables)
363                 {
364                         var outerValue = innerValue;
365                         for (int i = 1; i < nullables; i++) {
366                                 Type type = Globals.TypeOfNullable.MakeGenericType (innerType);
367                                 outerValue = Activator.CreateInstance (type, new object[] { outerValue });
368                                 innerType = type;
369                         }
370                         return Activator.CreateInstance (outerType, new object[] { outerValue });
371                 }
372
373
374                 void ReadCollection (CollectionDataContract collectionContract)
375                 {
376                         Type type = collectionContract.UnderlyingType;
377                         Type itemType = collectionContract.ItemType;
378                         bool isArray = (collectionContract.Kind == CollectionKind.Array);
379
380                         ConstructorInfo constructor = collectionContract.Constructor;
381
382                         if (type.IsInterface) {
383                                 switch (collectionContract.Kind) {
384                                 case CollectionKind.GenericDictionary:
385                                         type = Globals.TypeOfDictionaryGeneric.MakeGenericType (itemType.GetGenericArguments ());
386                                         constructor = type.GetConstructor (BindingFlags.Instance | BindingFlags.Public, null, Globals.EmptyTypeArray, null);
387                                         break;
388                                 case CollectionKind.Dictionary:
389                                         type = Globals.TypeOfHashtable;
390                                         constructor = XmlFormatGeneratorStatics.HashtableCtor;
391                                         break;
392                                 case CollectionKind.Collection:
393                                 case CollectionKind.GenericCollection:
394                                 case CollectionKind.Enumerable:
395                                 case CollectionKind.GenericEnumerable:
396                                 case CollectionKind.List:
397                                 case CollectionKind.GenericList:
398                                         type = itemType.MakeArrayType ();
399                                         isArray = true;
400                                         break;
401                                 }
402                         }
403                         string itemName = collectionContract.ItemName;
404                         string itemNs = collectionContract.StableName.Namespace;
405
406                         if (!isArray) {
407                                 if (type.IsValueType)
408                                         // FIXME: this is not what the original code does.
409                                         objectLocal = FormatterServices.GetUninitializedObject (type);
410                                 else {
411                                         objectLocal = constructor.Invoke (new object [0]);
412                                         context.AddNewObject (objectLocal);
413                                 }
414                         }
415
416                         int size = context.GetArraySize ();
417
418                         string objectId = context.GetObjectId ();
419
420                         bool canReadPrimitiveArray = false;
421                         if (isArray && TryReadPrimitiveArray (type, itemType, size))
422                                 canReadPrimitiveArray = true;
423
424                         if (!canReadPrimitiveArray) {
425                                 if (size == -1) {
426
427                                         object growingCollection = null;
428                                         if (isArray)
429                                                 growingCollection = Array.CreateInstance (itemType, 32);
430
431                                         int i = 0;
432                                         // FIXME: I cannot find i++ part, but without that it won't work as expected.
433                                         for (; i < int.MaxValue; i++) {
434                                                 if (IsStartElement (this.itemName, this.itemNamespace)) {
435                                                         context.IncrementItemCount (1);
436                                                         object value = ReadCollectionItem (collectionContract, itemType, itemName, itemNs);
437                                                         if (isArray) {
438                                                                 MethodInfo ensureArraySizeMethod = XmlFormatGeneratorStatics.EnsureArraySizeMethod.MakeGenericMethod (itemType);
439                                                                 growingCollection = ensureArraySizeMethod.Invoke (null, new object [] {growingCollection, i});
440                                                                 ((Array) growingCollection).SetValue (value, i);
441                                                         } else {
442                                                                 StoreCollectionValue (objectLocal, itemType, value, collectionContract);
443                                                         }
444                                                 }
445                                                 else if (IsEndElement ())
446                                                         break;
447                                                 else
448                                                         HandleUnexpectedItemInCollection (ref i);
449                                         }
450
451                                         if (isArray) {
452                                                 MethodInfo trimArraySizeMethod = XmlFormatGeneratorStatics.TrimArraySizeMethod.MakeGenericMethod (itemType);
453                                                 objectLocal = trimArraySizeMethod.Invoke (null, new object [] {growingCollection, i});
454                                                 context.AddNewObjectWithId (objectId, objectLocal);
455                                         }
456                                 } else {
457                                         context.IncrementItemCount (size);
458                                         if (isArray) {
459                                                 objectLocal = Array.CreateInstance (itemType, size);
460                                                 context.AddNewObject (objectLocal);
461                                         }
462                                         // FIXME: I cannot find j++ part, but without that it won't work as expected.
463                                         for (int j = 0; j < size; j++) {
464                                                 if (IsStartElement (this.itemName, this.itemNamespace)) {
465                                                         var itemValue = ReadCollectionItem (collectionContract, itemType, itemName, itemNs);
466                                                         if (isArray)
467                                                                 ((Array) objectLocal).SetValue (itemValue, j);
468                                                         else
469                                                                 StoreCollectionValue (objectLocal, itemType, itemValue, collectionContract);
470                                                 }
471                                                 else
472                                                         HandleUnexpectedItemInCollection (ref j);
473                                         }
474                                         context.CheckEndOfArray (xmlReader, size, this.itemName, this.itemNamespace);
475                                 }
476                         }
477                         else
478                                 context.AddNewObjectWithId (objectId, objectLocal);
479                 }
480
481                 void ReadGetOnlyCollection (CollectionDataContract collectionContract)
482                 {
483                         Type type = collectionContract.UnderlyingType;
484                         Type itemType = collectionContract.ItemType;
485                         bool isArray = (collectionContract.Kind == CollectionKind.Array);
486                         string itemName = collectionContract.ItemName;
487                         string itemNs = collectionContract.StableName.Namespace;
488
489                         objectLocal = context.GetCollectionMember ();
490
491                         //check that items are actually going to be deserialized into the collection
492                         if (IsStartElement (this.itemName, this.itemNamespace)) {
493                                 if (objectLocal == null)
494                                         XmlObjectSerializerReadContext.ThrowNullValueReturnedForGetOnlyCollectionException (type);
495                                 else {
496                                         int size = 0;
497                                         if (isArray)
498                                                 size = ((Array) objectLocal).Length;
499                                         context.AddNewObject (objectLocal);
500                                         for (int i = 0; i < int.MaxValue;) {
501                                                 if (IsStartElement (this.itemName, this.itemNamespace)) {
502                                                         context.IncrementItemCount (1);
503                                                         var value = ReadCollectionItem (collectionContract, itemType, itemName, itemNs);
504                                                         if (isArray) {
505                                                                 if (size == i)
506                                                                         XmlObjectSerializerReadContext.ThrowArrayExceededSizeException (size, type);
507                                                                 else
508                                                                         ((Array) objectLocal).SetValue (value, i);
509                                                         } else {
510                                                                 StoreCollectionValue (objectLocal, itemType, value, collectionContract);
511                                                         }
512                                                 }
513                                                 else if (IsEndElement())
514                                                         break;
515                                                 else
516                                                         HandleUnexpectedItemInCollection (ref i);
517                                         }
518                                         context.CheckEndOfArray (xmlReader, size, this.itemName, this.itemNamespace);
519                                 }
520                         }
521                 }
522
523                 bool TryReadPrimitiveArray (Type type, Type itemType, int size)
524                 {
525                         PrimitiveDataContract primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract (itemType);
526                         if (primitiveContract == null)
527                                 return false;
528
529                         string readArrayMethod = null;
530                         switch (Type.GetTypeCode (itemType))
531                         {
532                         case TypeCode.Boolean:
533                                 readArrayMethod = "TryReadBooleanArray";
534                         break;
535                         case TypeCode.DateTime:
536                                 readArrayMethod = "TryReadDateTimeArray";
537                         break;
538                         case TypeCode.Decimal:
539                                 readArrayMethod = "TryReadDecimalArray";
540                         break;
541                         case TypeCode.Int32:
542                                 readArrayMethod = "TryReadInt32Array";
543                         break;
544                         case TypeCode.Int64:
545                                 readArrayMethod = "TryReadInt64Array";
546                         break;
547                         case TypeCode.Single:
548                                 readArrayMethod = "TryReadSingleArray";
549                         break;
550                         case TypeCode.Double:
551                                 readArrayMethod = "TryReadDoubleArray";
552                                 break;
553                         default:
554                                 break;
555                         }
556                         if (readArrayMethod != null) {
557                                 var mi = typeof (XmlReaderDelegator).GetMethod (readArrayMethod, Globals.ScanAllMembers);
558                                 mi.Invoke (xmlReader, new object [] {context, itemName, itemNamespace, size, objectLocal});
559                                 return true;
560                         }
561                         return false;
562                 }
563
564                 object ReadCollectionItem (CollectionDataContract collectionContract, Type itemType, string itemName, string itemNs)
565                 {
566                         if (collectionContract.Kind == CollectionKind.Dictionary || collectionContract.Kind == CollectionKind.GenericDictionary) {
567                                 context.ResetAttributes ();
568                                 return collectionContract.ItemContract.ReadXmlValue (xmlReader, context);
569                         }
570                         else
571                                 return ReadValue (itemType, itemName, itemNs);
572                 }
573
574                 void StoreCollectionValue (object collection, Type valueType, object value, CollectionDataContract collectionContract)
575                 {
576                         if (collectionContract.Kind == CollectionKind.GenericDictionary || collectionContract.Kind == CollectionKind.Dictionary) {
577                                 ClassDataContract keyValuePairContract = DataContract.GetDataContract (valueType) as ClassDataContract;
578                                 if (keyValuePairContract == null)
579                                         Fx.Assert ("Failed to create contract for KeyValuePair type");
580                                 DataMember keyMember = keyValuePairContract.Members [0];
581                                 DataMember valueMember = keyValuePairContract.Members [1];
582                                 object pkey = CodeInterpreter.GetMember (keyMember.MemberInfo, value);
583                                 object pvalue = CodeInterpreter.GetMember (valueMember.MemberInfo, value);
584                                 
585                                 collectionContract.AddMethod.Invoke (collection, new object [] {pkey, pvalue});
586                         }
587                         else
588                                 collectionContract.AddMethod.Invoke (collection, new object [] {value});
589                 }
590
591                 void HandleUnexpectedItemInCollection (ref int iterator)
592                 {
593                         if (IsStartElement ()) {
594                                 context.SkipUnknownElement (xmlReader);
595                                 iterator--;
596                         }
597                         else 
598                                 throw XmlObjectSerializerReadContext.CreateUnexpectedStateException (XmlNodeType.Element, xmlReader);
599                 }
600
601                 bool IsStartElement(XmlDictionaryString name, XmlDictionaryString ns)
602                 {
603                         return xmlReader.IsStartElement (name, ns);
604                 }
605
606                 bool IsStartElement()
607                 {
608                         return xmlReader.IsStartElement ();
609                 }
610
611                 bool IsEndElement ()
612                 {
613                         return xmlReader.NodeType == XmlNodeType.EndElement;
614                 }
615         }
616 }