1 //-----------------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 //-----------------------------------------------------------------------------
4 namespace System.Runtime.Serialization.Json
7 using System.Collections.Generic;
8 using System.Reflection;
9 #if !NO_DYNAMIC_CODEGEN
10 using System.Reflection.Emit;
13 using System.Runtime.Serialization.Diagnostics.Application;
14 using System.Security;
15 using System.Security.Permissions;
18 delegate object JsonFormatClassReaderDelegate(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContextComplexJson context, XmlDictionaryString emptyDictionaryString, XmlDictionaryString[] memberNames);
19 delegate object JsonFormatCollectionReaderDelegate(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContextComplexJson context, XmlDictionaryString emptyDictionaryString, XmlDictionaryString itemName, CollectionDataContract collectionContract);
20 delegate void JsonFormatGetOnlyCollectionReaderDelegate(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContextComplexJson context, XmlDictionaryString emptyDictionaryString, XmlDictionaryString itemName, CollectionDataContract collectionContract);
22 sealed partial class JsonFormatReaderGenerator
24 [Fx.Tag.SecurityNote(Critical = "Holds instance of CriticalHelper which keeps state that was produced within an assert.")]
26 CriticalHelper helper;
28 [Fx.Tag.SecurityNote(Critical = "Initializes SecurityCritical field 'helper'.")]
30 public JsonFormatReaderGenerator()
32 helper = new CriticalHelper();
35 [Fx.Tag.SecurityNote(Critical = "Accesses SecurityCritical helper class 'CriticalHelper'.")]
37 public JsonFormatClassReaderDelegate GenerateClassReader(ClassDataContract classContract)
43 if (TD.DCJsonGenReaderStartIsEnabled())
45 TD.DCJsonGenReaderStart("Class", classContract.UnderlyingType.FullName);
48 return helper.GenerateClassReader(classContract);
52 if (TD.DCJsonGenReaderStopIsEnabled())
54 TD.DCJsonGenReaderStop();
59 [Fx.Tag.SecurityNote(Critical = "Accesses SecurityCritical helper class 'CriticalHelper'.")]
61 public JsonFormatCollectionReaderDelegate GenerateCollectionReader(CollectionDataContract collectionContract)
65 if (TD.DCJsonGenReaderStartIsEnabled())
67 TD.DCJsonGenReaderStart("Collection", collectionContract.StableName.Name);
70 return helper.GenerateCollectionReader(collectionContract);
75 if (TD.DCJsonGenReaderStopIsEnabled())
77 TD.DCJsonGenReaderStop();
83 [Fx.Tag.SecurityNote(Critical = "Accesses SecurityCritical helper class 'CriticalHelper'.")]
85 public JsonFormatGetOnlyCollectionReaderDelegate GenerateGetOnlyCollectionReader(CollectionDataContract collectionContract)
90 if (TD.DCJsonGenReaderStartIsEnabled())
92 TD.DCJsonGenReaderStart("GetOnlyCollection", collectionContract.UnderlyingType.FullName);
95 return helper.GenerateGetOnlyCollectionReader(collectionContract);
100 if (TD.DCJsonGenReaderStopIsEnabled())
102 TD.DCJsonGenReaderStop();
107 #if !NO_DYNAMIC_CODEGEN
108 [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - handles all aspects of IL generation including initializing the DynamicMethod."
109 + "Changes to how IL generated could affect how data is deserialized and what gets access to data, "
110 + "therefore we mark it for review so that changes to generation logic are reviewed.")]
111 partial class CriticalHelper
114 LocalBuilder objectLocal;
116 ArgBuilder xmlReaderArg;
117 ArgBuilder contextArg;
118 ArgBuilder memberNamesArg;
119 ArgBuilder collectionContractArg;
120 ArgBuilder emptyDictionaryStringArg;
122 public JsonFormatClassReaderDelegate GenerateClassReader(ClassDataContract classContract)
124 ilg = new CodeGenerator();
125 bool memberAccessFlag = classContract.RequiresMemberAccessForRead(null);
128 BeginMethod(ilg, "Read" + classContract.StableName.Name + "FromJson", typeof(JsonFormatClassReaderDelegate), memberAccessFlag);
130 catch (SecurityException securityException)
132 if (memberAccessFlag && securityException.PermissionType.Equals(typeof(ReflectionPermission)))
134 classContract.RequiresMemberAccessForRead(securityException);
142 DemandSerializationFormatterPermission(classContract);
143 DemandMemberAccessPermission(memberAccessFlag);
144 CreateObject(classContract);
145 ilg.Call(contextArg, XmlFormatGeneratorStatics.AddNewObjectMethod, objectLocal);
146 InvokeOnDeserializing(classContract);
147 if (classContract.IsISerializable)
148 ReadISerializable(classContract);
150 ReadClass(classContract);
151 if (Globals.TypeOfIDeserializationCallback.IsAssignableFrom(classContract.UnderlyingType))
152 ilg.Call(objectLocal, JsonFormatGeneratorStatics.OnDeserializationMethod, null);
153 InvokeOnDeserialized(classContract);
154 if (!InvokeFactoryMethod(classContract))
156 ilg.Load(objectLocal);
157 // Do a conversion back from DateTimeOffsetAdapter to DateTimeOffset after deserialization.
158 // DateTimeOffsetAdapter is used here for deserialization purposes to bypass the ISerializable implementation
159 // on DateTimeOffset; which does not work in partial trust.
161 if (classContract.UnderlyingType == Globals.TypeOfDateTimeOffsetAdapter)
163 ilg.ConvertValue(objectLocal.LocalType, Globals.TypeOfDateTimeOffsetAdapter);
164 ilg.Call(XmlFormatGeneratorStatics.GetDateTimeOffsetMethod);
165 ilg.ConvertValue(Globals.TypeOfDateTimeOffset, ilg.CurrentMethod.ReturnType);
169 ilg.ConvertValue(objectLocal.LocalType, ilg.CurrentMethod.ReturnType);
172 return (JsonFormatClassReaderDelegate)ilg.EndMethod();
175 public JsonFormatCollectionReaderDelegate GenerateCollectionReader(CollectionDataContract collectionContract)
177 ilg = GenerateCollectionReaderHelper(collectionContract, false /*isGetOnlyCollection*/);
178 ReadCollection(collectionContract);
179 ilg.Load(objectLocal);
180 ilg.ConvertValue(objectLocal.LocalType, ilg.CurrentMethod.ReturnType);
181 return (JsonFormatCollectionReaderDelegate)ilg.EndMethod();
184 public JsonFormatGetOnlyCollectionReaderDelegate GenerateGetOnlyCollectionReader(CollectionDataContract collectionContract)
186 ilg = GenerateCollectionReaderHelper(collectionContract, true /*isGetOnlyCollection*/);
187 ReadGetOnlyCollection(collectionContract);
188 return (JsonFormatGetOnlyCollectionReaderDelegate)ilg.EndMethod();
191 CodeGenerator GenerateCollectionReaderHelper(CollectionDataContract collectionContract, bool isGetOnlyCollection)
193 ilg = new CodeGenerator();
194 bool memberAccessFlag = collectionContract.RequiresMemberAccessForRead(null);
197 if (isGetOnlyCollection)
199 BeginMethod(ilg, "Read" + collectionContract.StableName.Name + "FromJson" + "IsGetOnly", typeof(JsonFormatGetOnlyCollectionReaderDelegate), memberAccessFlag);
203 BeginMethod(ilg, "Read" + collectionContract.StableName.Name + "FromJson", typeof(JsonFormatCollectionReaderDelegate), memberAccessFlag);
206 catch (SecurityException securityException)
208 if (memberAccessFlag && securityException.PermissionType.Equals(typeof(ReflectionPermission)))
210 collectionContract.RequiresMemberAccessForRead(securityException);
218 DemandMemberAccessPermission(memberAccessFlag);
219 collectionContractArg = ilg.GetArg(4);
223 void BeginMethod(CodeGenerator ilg, string methodName, Type delegateType, bool allowPrivateMemberAccess)
226 ilg.BeginMethod(methodName, delegateType, allowPrivateMemberAccess);
229 MethodInfo signature = delegateType.GetMethod("Invoke");
230 ParameterInfo[] parameters = signature.GetParameters();
231 Type[] paramTypes = new Type[parameters.Length];
232 for (int i = 0; i < parameters.Length; i++)
233 paramTypes[i] = parameters[i].ParameterType;
235 DynamicMethod dynamicMethod = new DynamicMethod(methodName, signature.ReturnType, paramTypes, typeof(JsonFormatReaderGenerator).Module, allowPrivateMemberAccess);
236 ilg.BeginMethod(dynamicMethod, delegateType, methodName, paramTypes, allowPrivateMemberAccess);
242 xmlReaderArg = ilg.GetArg(0);
243 contextArg = ilg.GetArg(1);
244 emptyDictionaryStringArg = ilg.GetArg(2);
245 memberNamesArg = ilg.GetArg(3);
248 void DemandMemberAccessPermission(bool memberAccessFlag)
250 if (memberAccessFlag)
252 ilg.Call(contextArg, XmlFormatGeneratorStatics.DemandMemberAccessPermissionMethod);
256 void DemandSerializationFormatterPermission(ClassDataContract classContract)
258 if (!classContract.HasDataContract && !classContract.IsNonAttributedType)
260 ilg.Call(contextArg, XmlFormatGeneratorStatics.DemandSerializationFormatterPermissionMethod);
265 void CreateObject(ClassDataContract classContract)
267 Type type = objectType = classContract.UnderlyingType;
268 if (type.IsValueType && !classContract.IsNonAttributedType)
269 type = Globals.TypeOfValueType;
271 objectLocal = ilg.DeclareLocal(type, "objectDeserialized");
273 if (classContract.UnderlyingType == Globals.TypeOfDBNull)
275 ilg.LoadMember(Globals.TypeOfDBNull.GetField("Value"));
276 ilg.Stloc(objectLocal);
278 else if (classContract.IsNonAttributedType)
280 if (type.IsValueType)
282 ilg.Ldloca(objectLocal);
287 ilg.New(classContract.GetNonAttributedTypeConstructor());
288 ilg.Stloc(objectLocal);
293 ilg.Call(null, JsonFormatGeneratorStatics.GetUninitializedObjectMethod, DataContract.GetIdForInitialization(classContract));
294 ilg.ConvertValue(Globals.TypeOfObject, type);
295 ilg.Stloc(objectLocal);
299 void InvokeOnDeserializing(ClassDataContract classContract)
301 if (classContract.BaseContract != null)
302 InvokeOnDeserializing(classContract.BaseContract);
303 if (classContract.OnDeserializing != null)
305 ilg.LoadAddress(objectLocal);
306 ilg.ConvertAddress(objectLocal.LocalType, objectType);
307 ilg.Load(contextArg);
308 ilg.LoadMember(XmlFormatGeneratorStatics.GetStreamingContextMethod);
309 ilg.Call(classContract.OnDeserializing);
313 void InvokeOnDeserialized(ClassDataContract classContract)
315 if (classContract.BaseContract != null)
316 InvokeOnDeserialized(classContract.BaseContract);
317 if (classContract.OnDeserialized != null)
319 ilg.LoadAddress(objectLocal);
320 ilg.ConvertAddress(objectLocal.LocalType, objectType);
321 ilg.Load(contextArg);
322 ilg.LoadMember(XmlFormatGeneratorStatics.GetStreamingContextMethod);
323 ilg.Call(classContract.OnDeserialized);
327 bool HasFactoryMethod(ClassDataContract classContract)
329 return Globals.TypeOfIObjectReference.IsAssignableFrom(classContract.UnderlyingType);
332 bool InvokeFactoryMethod(ClassDataContract classContract)
334 if (HasFactoryMethod(classContract))
336 ilg.Load(contextArg);
337 ilg.LoadAddress(objectLocal);
338 ilg.ConvertAddress(objectLocal.LocalType, Globals.TypeOfIObjectReference);
339 ilg.Load(Globals.NewObjectId);
340 ilg.Call(XmlFormatGeneratorStatics.GetRealObjectMethod);
341 ilg.ConvertValue(Globals.TypeOfObject, ilg.CurrentMethod.ReturnType);
347 void ReadClass(ClassDataContract classContract)
349 if (classContract.HasExtensionData)
351 LocalBuilder extensionDataLocal = ilg.DeclareLocal(Globals.TypeOfExtensionDataObject, "extensionData");
352 ilg.New(JsonFormatGeneratorStatics.ExtensionDataObjectCtor);
353 ilg.Store(extensionDataLocal);
354 ReadMembers(classContract, extensionDataLocal);
356 ClassDataContract currentContract = classContract;
357 while (currentContract != null)
359 MethodInfo extensionDataSetMethod = currentContract.ExtensionDataSetMethod;
360 if (extensionDataSetMethod != null)
361 ilg.Call(objectLocal, extensionDataSetMethod, extensionDataLocal);
362 currentContract = currentContract.BaseContract;
366 ReadMembers(classContract, null /*extensionDataLocal*/);
369 void ReadMembers(ClassDataContract classContract, LocalBuilder extensionDataLocal)
371 int memberCount = classContract.MemberNames.Length;
372 ilg.Call(contextArg, XmlFormatGeneratorStatics.IncrementItemCountMethod, memberCount);
374 BitFlagsGenerator expectedElements = new BitFlagsGenerator(memberCount, ilg, classContract.UnderlyingType.Name + "_ExpectedElements");
375 byte[] requiredElements = new byte[expectedElements.GetLocalCount()];
376 SetRequiredElements(classContract, requiredElements);
377 SetExpectedElements(expectedElements, 0 /*startIndex*/);
379 LocalBuilder memberIndexLocal = ilg.DeclareLocal(Globals.TypeOfInt, "memberIndex", -1);
380 Label throwDuplicateMemberLabel = ilg.DefineLabel();
381 Label throwMissingRequiredMembersLabel = ilg.DefineLabel();
383 object forReadElements = ilg.For(null, null, null);
384 ilg.Call(null, XmlFormatGeneratorStatics.MoveToNextElementMethod, xmlReaderArg);
385 ilg.IfFalseBreak(forReadElements);
386 ilg.Call(contextArg, JsonFormatGeneratorStatics.GetJsonMemberIndexMethod, xmlReaderArg, memberNamesArg, memberIndexLocal, extensionDataLocal);
389 Label[] memberLabels = ilg.Switch(memberCount);
390 ReadMembers(classContract, expectedElements, memberLabels, throwDuplicateMemberLabel, memberIndexLocal);
398 CheckRequiredElements(expectedElements, requiredElements, throwMissingRequiredMembersLabel);
399 Label endOfTypeLabel = ilg.DefineLabel();
400 ilg.Br(endOfTypeLabel);
402 ilg.MarkLabel(throwDuplicateMemberLabel);
403 ilg.Call(null, JsonFormatGeneratorStatics.ThrowDuplicateMemberExceptionMethod, objectLocal, memberNamesArg, memberIndexLocal);
405 ilg.MarkLabel(throwMissingRequiredMembersLabel);
406 ilg.Load(objectLocal);
407 ilg.ConvertValue(objectLocal.LocalType, Globals.TypeOfObject);
408 ilg.Load(memberNamesArg);
409 expectedElements.LoadArray();
410 LoadArray(requiredElements, "requiredElements");
411 ilg.Call(JsonFormatGeneratorStatics.ThrowMissingRequiredMembersMethod);
413 ilg.MarkLabel(endOfTypeLabel);
416 int ReadMembers(ClassDataContract classContract, BitFlagsGenerator expectedElements,
417 Label[] memberLabels, Label throwDuplicateMemberLabel, LocalBuilder memberIndexLocal)
419 int memberCount = (classContract.BaseContract == null) ? 0 :
420 ReadMembers(classContract.BaseContract, expectedElements, memberLabels, throwDuplicateMemberLabel, memberIndexLocal);
422 for (int i = 0; i < classContract.Members.Count; i++, memberCount++)
424 DataMember dataMember = classContract.Members[i];
425 Type memberType = dataMember.MemberType;
426 ilg.Case(memberLabels[memberCount], dataMember.Name);
427 ilg.Set(memberIndexLocal, memberCount);
428 expectedElements.Load(memberCount);
429 ilg.Brfalse(throwDuplicateMemberLabel);
430 LocalBuilder value = null;
431 if (dataMember.IsGetOnlyCollection)
433 ilg.LoadAddress(objectLocal);
434 ilg.LoadMember(dataMember.MemberInfo);
435 value = ilg.DeclareLocal(memberType, dataMember.Name + "Value");
437 ilg.Call(contextArg, XmlFormatGeneratorStatics.StoreCollectionMemberInfoMethod, value);
438 ReadValue(memberType, dataMember.Name);
442 value = ReadValue(memberType, dataMember.Name);
443 ilg.LoadAddress(objectLocal);
444 ilg.ConvertAddress(objectLocal.LocalType, objectType);
446 ilg.StoreMember(dataMember.MemberInfo);
448 ResetExpectedElements(expectedElements, memberCount);
454 void CheckRequiredElements(BitFlagsGenerator expectedElements, byte[] requiredElements, Label throwMissingRequiredMembersLabel)
456 for (int i = 0; i < requiredElements.Length; i++)
458 ilg.Load(expectedElements.GetLocal(i));
459 ilg.Load(requiredElements[i]);
463 ilg.Brfalse(throwMissingRequiredMembersLabel);
467 void LoadArray(byte[] array, string name)
469 LocalBuilder localArray = ilg.DeclareLocal(Globals.TypeOfByteArray, name);
470 ilg.NewArray(typeof(byte), array.Length);
471 ilg.Store(localArray);
472 for (int i = 0; i < array.Length; i++)
474 ilg.StoreArrayElement(localArray, i, array[i]);
476 ilg.Load(localArray);
479 int SetRequiredElements(ClassDataContract contract, byte[] requiredElements)
481 int memberCount = (contract.BaseContract == null) ? 0 :
482 SetRequiredElements(contract.BaseContract, requiredElements);
483 List<DataMember> members = contract.Members;
484 for (int i = 0; i < members.Count; i++, memberCount++)
486 if (members[i].IsRequired)
488 BitFlagsGenerator.SetBit(requiredElements, memberCount);
494 void SetExpectedElements(BitFlagsGenerator expectedElements, int startIndex)
496 int memberCount = expectedElements.GetBitCount();
497 for (int i = startIndex; i < memberCount; i++)
499 expectedElements.Store(i, true);
503 void ResetExpectedElements(BitFlagsGenerator expectedElements, int index)
505 expectedElements.Store(index, false);
508 void ReadISerializable(ClassDataContract classContract)
510 ConstructorInfo ctor = classContract.UnderlyingType.GetConstructor(Globals.ScanAllMembers, null, JsonFormatGeneratorStatics.SerInfoCtorArgs, null);
512 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.SerializationInfo_ConstructorNotFound, DataContract.GetClrTypeFullName(classContract.UnderlyingType))));
513 ilg.LoadAddress(objectLocal);
514 ilg.ConvertAddress(objectLocal.LocalType, objectType);
515 ilg.Call(contextArg, XmlFormatGeneratorStatics.ReadSerializationInfoMethod, xmlReaderArg, classContract.UnderlyingType);
516 ilg.Load(contextArg);
517 ilg.LoadMember(XmlFormatGeneratorStatics.GetStreamingContextMethod);
521 LocalBuilder ReadValue(Type type, string name)
523 LocalBuilder value = ilg.DeclareLocal(type, "valueRead");
524 LocalBuilder nullableValue = null;
526 while (type.IsGenericType && type.GetGenericTypeDefinition() == Globals.TypeOfNullable)
529 type = type.GetGenericArguments()[0];
532 PrimitiveDataContract primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract(type);
533 if ((primitiveContract != null && primitiveContract.UnderlyingType != Globals.TypeOfObject) || nullables != 0 || type.IsValueType)
535 LocalBuilder objectId = ilg.DeclareLocal(Globals.TypeOfString, "objectIdRead");
536 ilg.Call(contextArg, XmlFormatGeneratorStatics.ReadAttributesMethod, xmlReaderArg);
537 ilg.Call(contextArg, XmlFormatGeneratorStatics.ReadIfNullOrRefMethod, xmlReaderArg, type, DataContract.IsTypeSerializable(type));
540 ilg.If(objectId, Cmp.EqualTo, Globals.NullObjectId);
543 ilg.LoadAddress(value);
544 ilg.InitObj(value.LocalType);
546 else if (type.IsValueType)
547 ThrowSerializationException(SR.GetString(SR.ValueTypeCannotBeNull, DataContract.GetClrTypeFullName(type)));
556 // Compare against Globals.NewObjectId, which is set to string.Empty
557 ilg.ElseIfIsEmptyString(objectId);
558 ilg.Call(contextArg, XmlFormatGeneratorStatics.GetObjectIdMethod);
560 if (type.IsValueType)
562 ilg.IfNotIsEmptyString(objectId);
563 ThrowSerializationException(SR.GetString(SR.ValueTypeCannotHaveId, DataContract.GetClrTypeFullName(type)));
568 nullableValue = value;
569 value = ilg.DeclareLocal(type, "innerValueRead");
572 if (primitiveContract != null && primitiveContract.UnderlyingType != Globals.TypeOfObject)
574 ilg.Call(xmlReaderArg, primitiveContract.XmlFormatReaderMethod);
576 if (!type.IsValueType)
577 ilg.Call(contextArg, XmlFormatGeneratorStatics.AddNewObjectMethod, value);
581 InternalDeserialize(value, type, name);
585 if (type.IsValueType)
586 ThrowSerializationException(SR.GetString(SR.ValueTypeCannotHaveRef, DataContract.GetClrTypeFullName(type)));
589 ilg.Call(contextArg, XmlFormatGeneratorStatics.GetExistingObjectMethod, objectId, type, name, string.Empty);
590 ilg.ConvertValue(Globals.TypeOfObject, type);
595 if (nullableValue != null)
597 ilg.If(objectId, Cmp.NotEqualTo, Globals.NullObjectId);
598 WrapNullableObject(value, nullableValue, nullables);
600 value = nullableValue;
605 InternalDeserialize(value, type, name);
611 void InternalDeserialize(LocalBuilder value, Type type, string name)
613 ilg.Load(contextArg);
614 ilg.Load(xmlReaderArg);
615 Type declaredType = type.IsPointer ? Globals.TypeOfReflectionPointer : type;
616 ilg.Load(DataContract.GetId(declaredType.TypeHandle));
617 ilg.Ldtoken(declaredType);
620 ilg.Load(string.Empty);
621 ilg.Call(XmlFormatGeneratorStatics.InternalDeserializeMethod);
624 ilg.Call(JsonFormatGeneratorStatics.UnboxPointer);
626 ilg.ConvertValue(Globals.TypeOfObject, type);
630 void WrapNullableObject(LocalBuilder innerValue, LocalBuilder outerValue, int nullables)
632 Type innerType = innerValue.LocalType, outerType = outerValue.LocalType;
633 ilg.LoadAddress(outerValue);
634 ilg.Load(innerValue);
635 for (int i = 1; i < nullables; i++)
637 Type type = Globals.TypeOfNullable.MakeGenericType(innerType);
638 ilg.New(type.GetConstructor(new Type[] { innerType }));
641 ilg.Call(outerType.GetConstructor(new Type[] { innerType }));
644 void ReadCollection(CollectionDataContract collectionContract)
646 Type type = collectionContract.UnderlyingType;
647 Type itemType = collectionContract.ItemType;
648 bool isArray = (collectionContract.Kind == CollectionKind.Array);
649 ConstructorInfo constructor = collectionContract.Constructor;
650 if (type.IsInterface)
652 switch (collectionContract.Kind)
654 case CollectionKind.GenericDictionary:
655 type = Globals.TypeOfDictionaryGeneric.MakeGenericType(itemType.GetGenericArguments());
656 constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Globals.EmptyTypeArray, null);
658 case CollectionKind.Dictionary:
659 type = Globals.TypeOfHashtable;
660 constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Globals.EmptyTypeArray, null);
662 case CollectionKind.Collection:
663 case CollectionKind.GenericCollection:
664 case CollectionKind.Enumerable:
665 case CollectionKind.GenericEnumerable:
666 case CollectionKind.List:
667 case CollectionKind.GenericList:
668 type = itemType.MakeArrayType();
674 objectLocal = ilg.DeclareLocal(type, "objectDeserialized");
677 if (type.IsValueType)
679 ilg.Ldloca(objectLocal);
684 ilg.New(constructor);
685 ilg.Stloc(objectLocal);
686 ilg.Call(contextArg, XmlFormatGeneratorStatics.AddNewObjectMethod, objectLocal);
690 bool canReadSimpleDictionary = collectionContract.Kind == CollectionKind.Dictionary ||
691 collectionContract.Kind == CollectionKind.GenericDictionary;
692 if (canReadSimpleDictionary)
694 ilg.Load(contextArg);
695 ilg.LoadMember(JsonFormatGeneratorStatics.UseSimpleDictionaryFormatReadProperty);
698 ReadSimpleDictionary(collectionContract, itemType);
703 LocalBuilder objectId = ilg.DeclareLocal(Globals.TypeOfString, "objectIdRead");
704 ilg.Call(contextArg, XmlFormatGeneratorStatics.GetObjectIdMethod);
707 bool canReadPrimitiveArray = false;
708 if (isArray && TryReadPrimitiveArray(itemType))
710 canReadPrimitiveArray = true;
714 LocalBuilder growingCollection = null;
717 growingCollection = ilg.DeclareLocal(type, "growingCollection");
718 ilg.NewArray(itemType, 32);
719 ilg.Stloc(growingCollection);
721 LocalBuilder i = ilg.DeclareLocal(Globals.TypeOfInt, "i");
722 object forLoop = ilg.For(i, 0, Int32.MaxValue);
724 IsStartElement(memberNamesArg, emptyDictionaryStringArg);
726 ilg.Call(contextArg, XmlFormatGeneratorStatics.IncrementItemCountMethod, 1);
727 LocalBuilder value = ReadCollectionItem(collectionContract, itemType);
730 MethodInfo ensureArraySizeMethod = XmlFormatGeneratorStatics.EnsureArraySizeMethod.MakeGenericMethod(itemType);
731 ilg.Call(null, ensureArraySizeMethod, growingCollection, i);
732 ilg.Stloc(growingCollection);
733 ilg.StoreArrayElement(growingCollection, i, value);
736 StoreCollectionValue(objectLocal, value, collectionContract);
742 HandleUnexpectedItemInCollection(i);
749 MethodInfo trimArraySizeMethod = XmlFormatGeneratorStatics.TrimArraySizeMethod.MakeGenericMethod(itemType);
750 ilg.Call(null, trimArraySizeMethod, growingCollection, i);
751 ilg.Stloc(objectLocal);
752 ilg.Call(contextArg, XmlFormatGeneratorStatics.AddNewObjectWithIdMethod, objectId, objectLocal);
755 if (canReadPrimitiveArray)
758 ilg.Call(contextArg, XmlFormatGeneratorStatics.AddNewObjectWithIdMethod, objectId, objectLocal);
762 if (canReadSimpleDictionary)
768 void ReadSimpleDictionary(CollectionDataContract collectionContract, Type keyValueType)
770 Type[] keyValueTypes = keyValueType.GetGenericArguments();
771 Type keyType = keyValueTypes[0];
772 Type valueType = keyValueTypes[1];
774 int keyTypeNullableDepth = 0;
775 Type keyTypeOriginal = keyType;
776 while (keyType.IsGenericType && keyType.GetGenericTypeDefinition() == Globals.TypeOfNullable)
778 keyTypeNullableDepth++;
779 keyType = keyType.GetGenericArguments()[0];
782 ClassDataContract keyValueDataContract = (ClassDataContract)collectionContract.ItemContract;
783 DataContract keyDataContract = keyValueDataContract.Members[0].MemberTypeContract;
785 KeyParseMode keyParseMode = KeyParseMode.Fail;
787 if (keyType == Globals.TypeOfString || keyType == Globals.TypeOfObject)
789 keyParseMode = KeyParseMode.AsString;
791 else if (keyType.IsEnum)
793 keyParseMode = KeyParseMode.UsingParseEnum;
795 else if (keyDataContract.ParseMethod != null)
797 keyParseMode = KeyParseMode.UsingCustomParse;
800 if (keyParseMode == KeyParseMode.Fail)
802 ThrowSerializationException(
804 SR.KeyTypeCannotBeParsedInSimpleDictionary,
805 DataContract.GetClrTypeFullName(collectionContract.UnderlyingType),
806 DataContract.GetClrTypeFullName(keyType)));
810 LocalBuilder nodeType = ilg.DeclareLocal(typeof(XmlNodeType), "nodeType");
812 ilg.BeginWhileCondition();
813 ilg.Call(xmlReaderArg, JsonFormatGeneratorStatics.MoveToContentMethod);
816 ilg.Load(XmlNodeType.EndElement);
817 ilg.BeginWhileBody(Cmp.NotEqualTo);
820 ilg.Load(XmlNodeType.Element);
821 ilg.If(Cmp.NotEqualTo);
822 ThrowUnexpectedStateException(XmlNodeType.Element);
825 ilg.Call(contextArg, XmlFormatGeneratorStatics.IncrementItemCountMethod, 1);
827 if (keyParseMode == KeyParseMode.UsingParseEnum)
832 ilg.Load(xmlReaderArg);
833 ilg.Call(JsonFormatGeneratorStatics.GetJsonMemberNameMethod);
835 if (keyParseMode == KeyParseMode.UsingParseEnum)
837 ilg.Call(JsonFormatGeneratorStatics.ParseEnumMethod);
838 ilg.ConvertValue(Globals.TypeOfObject, keyType);
840 else if (keyParseMode == KeyParseMode.UsingCustomParse)
842 ilg.Call(keyDataContract.ParseMethod);
844 LocalBuilder pairKey = ilg.DeclareLocal(keyType, "key");
846 if (keyTypeNullableDepth > 0)
848 LocalBuilder pairKeyNullable = ilg.DeclareLocal(keyTypeOriginal, "keyOriginal");
849 WrapNullableObject(pairKey, pairKeyNullable, keyTypeNullableDepth);
850 pairKey = pairKeyNullable;
853 LocalBuilder pairValue = ReadValue(valueType, String.Empty);
854 StoreKeyValuePair(objectLocal, collectionContract, pairKey, pairValue);
860 void ReadGetOnlyCollection(CollectionDataContract collectionContract)
862 Type type = collectionContract.UnderlyingType;
863 Type itemType = collectionContract.ItemType;
864 bool isArray = (collectionContract.Kind == CollectionKind.Array);
865 LocalBuilder size = ilg.DeclareLocal(Globals.TypeOfInt, "arraySize");
867 objectLocal = ilg.DeclareLocal(type, "objectDeserialized");
868 ilg.Load(contextArg);
869 ilg.LoadMember(XmlFormatGeneratorStatics.GetCollectionMemberMethod);
870 ilg.ConvertValue(Globals.TypeOfObject, type);
871 ilg.Stloc(objectLocal);
873 bool canReadSimpleDictionary = collectionContract.Kind == CollectionKind.Dictionary ||
874 collectionContract.Kind == CollectionKind.GenericDictionary;
875 if (canReadSimpleDictionary)
877 ilg.Load(contextArg);
878 ilg.LoadMember(JsonFormatGeneratorStatics.UseSimpleDictionaryFormatReadProperty);
881 ilg.If(objectLocal, Cmp.EqualTo, null);
882 ilg.Call(null, XmlFormatGeneratorStatics.ThrowNullValueReturnedForGetOnlyCollectionExceptionMethod, type);
885 ReadSimpleDictionary(collectionContract, itemType);
887 ilg.Call(contextArg, XmlFormatGeneratorStatics.CheckEndOfArrayMethod, xmlReaderArg, size, memberNamesArg, emptyDictionaryStringArg);
894 //check that items are actually going to be deserialized into the collection
895 IsStartElement(memberNamesArg, emptyDictionaryStringArg);
897 ilg.If(objectLocal, Cmp.EqualTo, null);
898 ilg.Call(null, XmlFormatGeneratorStatics.ThrowNullValueReturnedForGetOnlyCollectionExceptionMethod, type);
904 ilg.Load(objectLocal);
905 ilg.Call(XmlFormatGeneratorStatics.GetArrayLengthMethod);
909 LocalBuilder i = ilg.DeclareLocal(Globals.TypeOfInt, "i");
910 object forLoop = ilg.For(i, 0, Int32.MaxValue);
911 IsStartElement(memberNamesArg, emptyDictionaryStringArg);
913 ilg.Call(contextArg, XmlFormatGeneratorStatics.IncrementItemCountMethod, 1);
914 LocalBuilder value = ReadCollectionItem(collectionContract, itemType);
917 ilg.If(size, Cmp.EqualTo, i);
918 ilg.Call(null, XmlFormatGeneratorStatics.ThrowArrayExceededSizeExceptionMethod, size, type);
920 ilg.StoreArrayElement(objectLocal, i, value);
924 StoreCollectionValue(objectLocal, value, collectionContract);
930 HandleUnexpectedItemInCollection(i);
934 ilg.Call(contextArg, XmlFormatGeneratorStatics.CheckEndOfArrayMethod, xmlReaderArg, size, memberNamesArg, emptyDictionaryStringArg);
939 if (canReadSimpleDictionary)
945 bool TryReadPrimitiveArray(Type itemType)
947 PrimitiveDataContract primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract(itemType);
948 if (primitiveContract == null)
951 string readArrayMethod = null;
952 switch (Type.GetTypeCode(itemType))
954 case TypeCode.Boolean:
955 readArrayMethod = "TryReadBooleanArray";
957 case TypeCode.Decimal:
958 readArrayMethod = "TryReadDecimalArray";
961 readArrayMethod = "TryReadInt32Array";
964 readArrayMethod = "TryReadInt64Array";
966 case TypeCode.Single:
967 readArrayMethod = "TryReadSingleArray";
969 case TypeCode.Double:
970 readArrayMethod = "TryReadDoubleArray";
972 case TypeCode.DateTime:
973 readArrayMethod = "TryReadJsonDateTimeArray";
978 if (readArrayMethod != null)
980 ilg.Load(xmlReaderArg);
981 ilg.ConvertValue(typeof(XmlReaderDelegator), typeof(JsonReaderDelegator));
982 ilg.Load(contextArg);
983 ilg.Load(memberNamesArg);
985 ilg.Load(emptyDictionaryStringArg);
988 ilg.Ldloca(objectLocal);
989 ilg.Call(typeof(JsonReaderDelegator).GetMethod(readArrayMethod, Globals.ScanAllMembers));
995 LocalBuilder ReadCollectionItem(CollectionDataContract collectionContract, Type itemType)
997 if (collectionContract.Kind == CollectionKind.Dictionary || collectionContract.Kind == CollectionKind.GenericDictionary)
999 ilg.Call(contextArg, XmlFormatGeneratorStatics.ResetAttributesMethod);
1000 LocalBuilder value = ilg.DeclareLocal(itemType, "valueRead");
1001 ilg.Load(collectionContractArg);
1002 ilg.Call(JsonFormatGeneratorStatics.GetItemContractMethod);
1003 ilg.Call(JsonFormatGeneratorStatics.GetRevisedItemContractMethod);
1004 ilg.Load(xmlReaderArg);
1005 ilg.Load(contextArg);
1006 ilg.Call(JsonFormatGeneratorStatics.ReadJsonValueMethod);
1007 ilg.ConvertValue(Globals.TypeOfObject, itemType);
1013 return ReadValue(itemType, JsonGlobals.itemString);
1017 void StoreCollectionValue(LocalBuilder collection, LocalBuilder value, CollectionDataContract collectionContract)
1019 if (collectionContract.Kind == CollectionKind.GenericDictionary || collectionContract.Kind == CollectionKind.Dictionary)
1021 ClassDataContract keyValuePairContract = DataContract.GetDataContract(value.LocalType) as ClassDataContract;
1022 if (keyValuePairContract == null)
1024 Fx.Assert("Failed to create contract for KeyValuePair type");
1026 DataMember keyMember = keyValuePairContract.Members[0];
1027 DataMember valueMember = keyValuePairContract.Members[1];
1028 LocalBuilder pairKey = ilg.DeclareLocal(keyMember.MemberType, keyMember.Name);
1029 LocalBuilder pairValue = ilg.DeclareLocal(valueMember.MemberType, valueMember.Name);
1030 ilg.LoadAddress(value);
1031 ilg.LoadMember(keyMember.MemberInfo);
1033 ilg.LoadAddress(value);
1034 ilg.LoadMember(valueMember.MemberInfo);
1035 ilg.Stloc(pairValue);
1037 StoreKeyValuePair(collection, collectionContract, pairKey, pairValue);
1041 ilg.Call(collection, collectionContract.AddMethod, value);
1042 if (collectionContract.AddMethod.ReturnType != Globals.TypeOfVoid)
1047 void StoreKeyValuePair(LocalBuilder collection, CollectionDataContract collectionContract, LocalBuilder pairKey, LocalBuilder pairValue)
1049 ilg.Call(collection, collectionContract.AddMethod, pairKey, pairValue);
1050 if (collectionContract.AddMethod.ReturnType != Globals.TypeOfVoid)
1054 void HandleUnexpectedItemInCollection(LocalBuilder iterator)
1058 ilg.Call(contextArg, XmlFormatGeneratorStatics.SkipUnknownElementMethod, xmlReaderArg);
1061 ThrowUnexpectedStateException(XmlNodeType.Element);
1065 void IsStartElement(ArgBuilder nameArg, ArgBuilder nsArg)
1067 ilg.Call(xmlReaderArg, JsonFormatGeneratorStatics.IsStartElementMethod2, nameArg, nsArg);
1070 void IsStartElement()
1072 ilg.Call(xmlReaderArg, JsonFormatGeneratorStatics.IsStartElementMethod0);
1077 ilg.Load(xmlReaderArg);
1078 ilg.LoadMember(JsonFormatGeneratorStatics.NodeTypeProperty);
1079 ilg.Load(XmlNodeType.EndElement);
1083 void ThrowUnexpectedStateException(XmlNodeType expectedState)
1085 ilg.Call(null, XmlFormatGeneratorStatics.CreateUnexpectedStateExceptionMethod, expectedState, xmlReaderArg);
1089 void ThrowSerializationException(string msg, params object[] values)
1091 if (values != null && values.Length > 0)
1092 ilg.CallStringFormat(msg, values);
1095 ThrowSerializationException();
1098 void ThrowSerializationException()
1100 ilg.New(JsonFormatGeneratorStatics.SerializationExceptionCtor);