Merge pull request #2372 from abock/dcs-iserializable-bxc37171
[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 = CodeInterpreter.ConvertValue (XmlFormatReaderGenerator.UnsafeGetUninitializedObject (DataContract.GetIdForInitialization (classContract)), Globals.TypeOfObject, type);
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 = CodeInterpreter.ConvertValue (context.GetRealObject ((IObjectReference) objectLocal, objectId), Globals.TypeOfObject, classContract.UnderlyingType);
176                                 return true;
177                         }
178                         return false;
179                 }
180
181                 void ReadISerializable (ClassDataContract classContract)
182                 {
183                         ConstructorInfo ctor = classContract.GetISerializableConstructor ();
184                         var info = context.ReadSerializationInfo (xmlReader, classContract.UnderlyingType);
185                         ctor.Invoke (objectLocal, new object [] {info, 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                         int requiredIndex = hasRequiredMembers ? firstRequiredMember : memberCount;
216
217                         while (XmlObjectSerializerReadContext.MoveToNextElement (xmlReader)) {
218                                 int idx; // used as in "switch (idx)" in the original source.
219                                 if (hasRequiredMembers)
220                                         idx = context.GetMemberIndexWithRequiredMembers (xmlReader, memberNames, memberNamespaces, memberIndex, (int) requiredIndex, extensionData);
221                                 else
222                                         idx = context.GetMemberIndex (xmlReader, memberNames, memberNamespaces, memberIndex, extensionData);
223
224                                 if (memberCount > 0)
225                                         ReadMembers (idx, classContract, requiredMembers, ref memberIndex, ref requiredIndex);
226                         }
227
228                         if (hasRequiredMembers)
229                         {
230                                 if (requiredIndex < memberCount)
231                                         XmlObjectSerializerReadContext.ThrowRequiredMemberMissingException (xmlReader, memberIndex, requiredIndex, memberNames);
232                         }
233                 }
234
235                 int ReadMembers (int index, ClassDataContract classContract, bool [] requiredMembers, ref int memberIndex, ref int requiredIndex)
236                 {
237                         int memberCount = (classContract.BaseContract == null) ? 0 : ReadMembers (index, classContract.BaseContract, requiredMembers,
238                         ref memberIndex, ref requiredIndex);
239                         
240                         if (memberCount <= index && index < memberCount + classContract.Members.Count) {
241                                 DataMember dataMember = classContract.Members [index - memberCount];
242                                 Type memberType = dataMember.MemberType;
243                                 if (dataMember.IsRequired) {
244                                         int nextRequiredIndex = index + 1;
245                                         for (; nextRequiredIndex < requiredMembers.Length; nextRequiredIndex++)
246                                                 if (requiredMembers [nextRequiredIndex])
247                                                         break;
248                                         requiredIndex = nextRequiredIndex;
249                                 }
250
251                                 if (dataMember.IsGetOnlyCollection) {
252                                         var value = CodeInterpreter.GetMember (dataMember.MemberInfo, objectLocal);
253                                         context.StoreCollectionMemberInfo (value);
254                                         ReadValue (memberType, dataMember.Name, classContract.StableName.Namespace);
255                                 } else {
256                                         var value = ReadValue (memberType, dataMember.Name, classContract.StableName.Namespace);
257                                         CodeInterpreter.SetMember (dataMember.MemberInfo, objectLocal, value);
258                                 }
259                                 memberIndex = index;
260                         }
261                         return memberCount + classContract.Members.Count;
262                 }
263
264                 bool[] GetRequiredMembers (ClassDataContract contract, out int firstRequiredMember)
265                 {
266                         int memberCount = contract.MemberNames.Length;
267                         bool [] requiredMembers = new bool [memberCount];
268                         GetRequiredMembers (contract, requiredMembers);
269                         for (firstRequiredMember = 0; firstRequiredMember < memberCount; firstRequiredMember++)
270                                 if (requiredMembers [firstRequiredMember])
271                                         break;
272                         return requiredMembers;
273                 }
274
275                 int GetRequiredMembers (ClassDataContract contract, bool[] requiredMembers)
276                 {
277                         int memberCount = (contract.BaseContract == null) ? 0 : GetRequiredMembers (contract.BaseContract, requiredMembers);
278                         List<DataMember> members = contract.Members;
279                         for (int i = 0; i < members.Count; i++, memberCount++)
280                                 requiredMembers [memberCount] = members [i].IsRequired;
281                         return memberCount;
282                 }
283
284                 object ReadValue (Type type, string name, string ns)
285                 {
286                         var valueType = type;
287                         object value = null;
288                         bool shouldAssignNullableValue = false;
289                         int nullables = 0;
290                         while (type.IsGenericType && type.GetGenericTypeDefinition () == Globals.TypeOfNullable) {
291                                 nullables++;
292                                 type = type.GetGenericArguments () [0];
293                         }
294                         
295                         PrimitiveDataContract primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract (type);
296                         if ((primitiveContract != null && primitiveContract.UnderlyingType != Globals.TypeOfObject) || nullables != 0 || type.IsValueType) {
297                                 context.ReadAttributes (xmlReader);
298                                 string objectId = context.ReadIfNullOrRef (xmlReader, type, DataContract.IsTypeSerializable (type));
299                                 // Deserialize null
300                 if (objectId == Globals.NullObjectId) {
301                                         
302                                         if (nullables != 0)
303                                                 value = Activator.CreateInstance (valueType);
304                                         else if (type.IsValueType)
305                                                 throw new SerializationException (SR.GetString (SR.ValueTypeCannotBeNull, DataContract.GetClrTypeFullName (type)));
306                                         else
307                                                 value = null;
308                                 } else if (objectId == string.Empty) {
309                                         // Deserialize value
310
311                                         // Compare against Globals.NewObjectId, which is set to string.Empty
312                                         
313                                         objectId = context.GetObjectId ();
314                                         
315                                         if (type.IsValueType) {
316                                                 if (!string.IsNullOrEmpty (objectId))
317                                                         throw new SerializationException (SR.GetString (SR.ValueTypeCannotHaveId, DataContract.GetClrTypeFullName(type)));
318                                         }
319                                         object innerValueRead = null;
320                                         if (nullables != 0)
321                                                 shouldAssignNullableValue = true;
322
323                                         if (primitiveContract != null && primitiveContract.UnderlyingType != Globals.TypeOfObject) {
324                                                 value = primitiveContract.XmlFormatReaderMethod.Invoke (xmlReader, new object [0]);
325                                                 if (!type.IsValueType)
326                                                         context.AddNewObject (value);
327                                         }
328                                         else
329                                                         value = InternalDeserialize (type, name, ns);
330                                 } else {
331                                         // Deserialize ref
332                                         if (type.IsValueType)
333                                                 throw new SerializationException (SR.GetString (SR.ValueTypeCannotHaveRef, DataContract.GetClrTypeFullName (type)));
334                                         else
335                                                 value = CodeInterpreter.ConvertValue (context.GetExistingObject (objectId, type, name, ns), Globals.TypeOfObject, type);
336                                 }
337
338                                 if (shouldAssignNullableValue) {
339                                         if (objectId != Globals.NullObjectId)
340                                                 value = WrapNullableObject (type, value, valueType, nullables);
341                                 }
342                         }
343                         else
344                                 value = InternalDeserialize (type, name, ns);
345
346                         return value;
347                 }
348
349                 object InternalDeserialize (Type type, string name, string ns)
350                 {
351                         Type declaredType = type.IsPointer ? Globals.TypeOfReflectionPointer : type;
352                         var obj = context.InternalDeserialize (xmlReader, DataContract.GetId (declaredType.TypeHandle), declaredType.TypeHandle, name, ns);
353
354                         if (type.IsPointer)
355                                 // wow, there is no way to convert void* to object in strongly typed way...
356                                 return XmlFormatGeneratorStatics.UnboxPointer.Invoke (null, new object [] {obj});
357                         else
358                                 return CodeInterpreter.ConvertValue (obj, Globals.TypeOfObject, type);
359                 }
360
361                 object WrapNullableObject (Type innerType, object innerValue, Type outerType, int nullables)
362                 {
363                         var outerValue = innerValue;
364                         for (int i = 1; i < nullables; i++) {
365                                 Type type = Globals.TypeOfNullable.MakeGenericType (innerType);
366                                 outerValue = Activator.CreateInstance (type, new object[] { outerValue });
367                                 innerType = type;
368                         }
369                         return Activator.CreateInstance (outerType, new object[] { outerValue });
370                 }
371
372
373                 void ReadCollection (CollectionDataContract collectionContract)
374                 {
375                         Type type = collectionContract.UnderlyingType;
376                         Type itemType = collectionContract.ItemType;
377                         bool isArray = (collectionContract.Kind == CollectionKind.Array);
378
379                         ConstructorInfo constructor = collectionContract.Constructor;
380
381                         if (type.IsInterface) {
382                                 switch (collectionContract.Kind) {
383                                 case CollectionKind.GenericDictionary:
384                                         type = Globals.TypeOfDictionaryGeneric.MakeGenericType (itemType.GetGenericArguments ());
385                                         constructor = type.GetConstructor (BindingFlags.Instance | BindingFlags.Public, null, Globals.EmptyTypeArray, null);
386                                         break;
387                                 case CollectionKind.Dictionary:
388                                         type = Globals.TypeOfHashtable;
389                                         constructor = XmlFormatGeneratorStatics.HashtableCtor;
390                                         break;
391                                 case CollectionKind.Collection:
392                                 case CollectionKind.GenericCollection:
393                                 case CollectionKind.Enumerable:
394                                 case CollectionKind.GenericEnumerable:
395                                 case CollectionKind.List:
396                                 case CollectionKind.GenericList:
397                                         type = itemType.MakeArrayType ();
398                                         isArray = true;
399                                         break;
400                                 }
401                         }
402                         string itemName = collectionContract.ItemName;
403                         string itemNs = collectionContract.StableName.Namespace;
404
405                         if (!isArray) {
406                                 if (type.IsValueType)
407                                         // FIXME: this is not what the original code does.
408                                         objectLocal = FormatterServices.GetUninitializedObject (type);
409                                 else {
410                                         objectLocal = constructor.Invoke (new object [0]);
411                                         context.AddNewObject (objectLocal);
412                                 }
413                         }
414
415                         int size = context.GetArraySize ();
416
417                         string objectId = context.GetObjectId ();
418
419                         bool canReadPrimitiveArray = false, readResult = false;
420                         if (isArray && TryReadPrimitiveArray (type, itemType, size, out readResult))
421                                 canReadPrimitiveArray = true;
422
423                         if (!readResult) {
424                                 if (size == -1) {
425
426                                         object growingCollection = null;
427                                         if (isArray)
428                                                 growingCollection = Array.CreateInstance (itemType, 32);
429
430                                         int i = 0;
431                                         // FIXME: I cannot find i++ part, but without that it won't work as expected.
432                                         for (; i < int.MaxValue; i++) {
433                                                 if (IsStartElement (this.itemName, this.itemNamespace)) {
434                                                         context.IncrementItemCount (1);
435                                                         object value = ReadCollectionItem (collectionContract, itemType, itemName, itemNs);
436                                                         if (isArray) {
437                                                                 MethodInfo ensureArraySizeMethod = XmlFormatGeneratorStatics.EnsureArraySizeMethod.MakeGenericMethod (itemType);
438                                                                 growingCollection = ensureArraySizeMethod.Invoke (null, new object [] {growingCollection, i});
439                                                                 ((Array) growingCollection).SetValue (value, i);
440                                                         } else {
441                                                                 StoreCollectionValue (objectLocal, itemType, value, collectionContract);
442                                                         }
443                                                 }
444                                                 else if (IsEndElement ())
445                                                         break;
446                                                 else
447                                                         HandleUnexpectedItemInCollection (ref i);
448                                         }
449
450                                         if (isArray) {
451                                                 MethodInfo trimArraySizeMethod = XmlFormatGeneratorStatics.TrimArraySizeMethod.MakeGenericMethod (itemType);
452                                                 objectLocal = trimArraySizeMethod.Invoke (null, new object [] {growingCollection, i});
453                                                 context.AddNewObjectWithId (objectId, objectLocal);
454                                         }
455                                 } else {
456                                         context.IncrementItemCount (size);
457                                         if (isArray) {
458                                                 objectLocal = Array.CreateInstance (itemType, size);
459                                                 context.AddNewObject (objectLocal);
460                                         }
461                                         // FIXME: I cannot find j++ part, but without that it won't work as expected.
462                                         for (int j = 0; j < size; j++) {
463                                                 if (IsStartElement (this.itemName, this.itemNamespace)) {
464                                                         var itemValue = ReadCollectionItem (collectionContract, itemType, itemName, itemNs);
465                                                         if (isArray)
466                                                                 ((Array) objectLocal).SetValue (itemValue, j);
467                                                         else
468                                                                 StoreCollectionValue (objectLocal, itemType, itemValue, collectionContract);
469                                                 }
470                                                 else
471                                                         HandleUnexpectedItemInCollection (ref j);
472                                         }
473                                         context.CheckEndOfArray (xmlReader, size, this.itemName, this.itemNamespace);
474                                 }
475                         }
476                         if (canReadPrimitiveArray)
477                                 context.AddNewObjectWithId (objectId, objectLocal);
478                 }
479
480                 void ReadGetOnlyCollection (CollectionDataContract collectionContract)
481                 {
482                         Type type = collectionContract.UnderlyingType;
483                         Type itemType = collectionContract.ItemType;
484                         bool isArray = (collectionContract.Kind == CollectionKind.Array);
485                         string itemName = collectionContract.ItemName;
486                         string itemNs = collectionContract.StableName.Namespace;
487
488                         objectLocal = context.GetCollectionMember ();
489
490                         //check that items are actually going to be deserialized into the collection
491                         if (IsStartElement (this.itemName, this.itemNamespace)) {
492                                 if (objectLocal == null)
493                                         XmlObjectSerializerReadContext.ThrowNullValueReturnedForGetOnlyCollectionException (type);
494                                 else {
495                                         int size = 0;
496                                         if (isArray)
497                                                 size = ((Array) objectLocal).Length;
498                                         context.AddNewObject (objectLocal);
499                                         for (int i = 0; i < int.MaxValue;) {
500                                                 if (IsStartElement (this.itemName, this.itemNamespace)) {
501                                                         context.IncrementItemCount (1);
502                                                         var value = ReadCollectionItem (collectionContract, itemType, itemName, itemNs);
503                                                         if (isArray) {
504                                                                 if (size == i)
505                                                                         XmlObjectSerializerReadContext.ThrowArrayExceededSizeException (size, type);
506                                                                 else
507                                                                         ((Array) objectLocal).SetValue (value, i);
508                                                         } else {
509                                                                 StoreCollectionValue (objectLocal, itemType, value, collectionContract);
510                                                         }
511                                                 }
512                                                 else if (IsEndElement())
513                                                         break;
514                                                 else
515                                                         HandleUnexpectedItemInCollection (ref i);
516                                         }
517                                         context.CheckEndOfArray (xmlReader, size, this.itemName, this.itemNamespace);
518                                 }
519                         }
520                 }
521
522                 bool TryReadPrimitiveArray (Type type, Type itemType, int size, out bool readResult)
523                 {
524                         readResult = false;
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                                 var args = new object [] {context, itemName, itemNamespace, size, objectLocal};
559                                 readResult = (bool) mi.Invoke (xmlReader, args);
560                                 objectLocal = args.Last ();
561                                 return true;
562                         }
563                         return false;
564                 }
565
566                 object ReadCollectionItem (CollectionDataContract collectionContract, Type itemType, string itemName, string itemNs)
567                 {
568                         if (collectionContract.Kind == CollectionKind.Dictionary || collectionContract.Kind == CollectionKind.GenericDictionary) {
569                                 context.ResetAttributes ();
570                                 return CodeInterpreter.ConvertValue (collectionContract.ItemContract.ReadXmlValue (xmlReader, context), Globals.TypeOfObject, itemType);
571                         }
572                         else
573                                 return ReadValue (itemType, itemName, itemNs);
574                 }
575
576                 void StoreCollectionValue (object collection, Type valueType, object value, CollectionDataContract collectionContract)
577                 {
578                         if (collectionContract.Kind == CollectionKind.GenericDictionary || collectionContract.Kind == CollectionKind.Dictionary) {
579                                 ClassDataContract keyValuePairContract = DataContract.GetDataContract (valueType) as ClassDataContract;
580                                 if (keyValuePairContract == null)
581                                         Fx.Assert ("Failed to create contract for KeyValuePair type");
582                                 DataMember keyMember = keyValuePairContract.Members [0];
583                                 DataMember valueMember = keyValuePairContract.Members [1];
584                                 object pkey = CodeInterpreter.GetMember (keyMember.MemberInfo, value);
585                                 object pvalue = CodeInterpreter.GetMember (valueMember.MemberInfo, value);
586                                 
587                                 collectionContract.AddMethod.Invoke (collection, new object [] {pkey, pvalue});
588                         }
589                         else
590                                 collectionContract.AddMethod.Invoke (collection, new object [] {value});
591                 }
592
593                 void HandleUnexpectedItemInCollection (ref int iterator)
594                 {
595                         if (IsStartElement ()) {
596                                 context.SkipUnknownElement (xmlReader);
597                                 iterator--;
598                         }
599                         else 
600                                 throw XmlObjectSerializerReadContext.CreateUnexpectedStateException (XmlNodeType.Element, xmlReader);
601                 }
602
603                 bool IsStartElement(XmlDictionaryString name, XmlDictionaryString ns)
604                 {
605                         return xmlReader.IsStartElement (name, ns);
606                 }
607
608                 bool IsStartElement()
609                 {
610                         return xmlReader.IsStartElement ();
611                 }
612
613                 bool IsEndElement ()
614                 {
615                         return xmlReader.NodeType == XmlNodeType.EndElement;
616                 }
617         }
618 }