JsonFormatReaderGenerator.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / NetFx35 / System.ServiceModel.Web / System / Runtime / Serialization / Json / JsonFormatReaderGenerator.cs / 4 / JsonFormatReaderGenerator.cs

                            //------------------------------------------------------------------------------ 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------------------------
namespace System.Runtime.Serialization.Json
{ 
    using System;
    using System.Collections.Generic; 
    using System.Reflection; 
    using System.Reflection.Emit;
    using System.Xml; 
    using System.Security;
    using System.Security.Permissions;
    using System.ServiceModel.Web;
 
    internal delegate object JsonFormatClassReaderDelegate(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContextComplexJson context, XmlDictionaryString emptyDictionaryString, XmlDictionaryString[] memberNames);
    internal delegate object JsonFormatCollectionReaderDelegate(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContextComplexJson context, XmlDictionaryString emptyDictionaryString, XmlDictionaryString itemName, CollectionDataContract collectionContract); 
    internal delegate void JsonFormatGetOnlyCollectionReaderDelegate(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContextComplexJson context, XmlDictionaryString emptyDictionaryString, XmlDictionaryString itemName, CollectionDataContract collectionContract); 

    internal sealed class JsonFormatReaderGenerator 
    {
        // 
        // Critical - holds instance of CriticalHelper which keeps state that was produced within an assert
        //  
        [SecurityCritical]
        CriticalHelper helper; 
 
        // 
        // Critical - initializes SecurityCritical field 'helper' 
        // 
        [SecurityCritical]
        public JsonFormatReaderGenerator()
        { 
            helper = new CriticalHelper();
        } 
 
        // 
        // Critical - accesses SecurityCritical helper class 'CriticalHelper' 
        // 
        [SecurityCritical]
        public JsonFormatClassReaderDelegate GenerateClassReader(ClassDataContract classContract)
        { 
            return helper.GenerateClassReader(classContract);
        } 
 
        // 
        // Critical - accesses SecurityCritical helper class 'CriticalHelper' 
        // 
        [SecurityCritical]
        public JsonFormatCollectionReaderDelegate GenerateCollectionReader(CollectionDataContract collectionContract)
        { 
            return helper.GenerateCollectionReader(collectionContract);
        } 
 
        /// 
        /// Critical - accesses SecurityCritical helper class 'CriticalHelper' 
        /// 
        [SecurityCritical]
        public JsonFormatGetOnlyCollectionReaderDelegate GenerateGetOnlyCollectionReader(CollectionDataContract collectionContract)
        { 
            return helper.GenerateGetOnlyCollectionReader(collectionContract);
        } 
 
        /// 
        /// Review - handles all aspects of IL generation including initializing the DynamicMethod. 
        ///          changes to how IL generated could affect how data is deserialized and what gets access to data,
        ///          therefore we mark it for review so that changes to generation logic are reviewed.
        /// 
        [SecurityRequiresReview(SecurityCriticalScope.Everything)] 
        class CriticalHelper
        { 
            CodeGenerator ilg; 
            LocalBuilder objectLocal;
            Type objectType; 
            ArgBuilder xmlReaderArg;
            ArgBuilder contextArg;
            ArgBuilder memberNamesArg;
            ArgBuilder collectionContractArg; 
            ArgBuilder emptyDictionaryStringArg;
 
            public JsonFormatClassReaderDelegate GenerateClassReader(ClassDataContract classContract) 
            {
                ilg = new CodeGenerator(); 
                bool memberAccessFlag = classContract.RequiresMemberAccessForRead(null) && RequiresJsonMemberAccessForRead(classContract.UnderlyingType);
                try
                {
                    BeginMethod(ilg, "Read" + classContract.StableName.Name + "FromJson", typeof(JsonFormatClassReaderDelegate), memberAccessFlag); 
                }
                catch (SecurityException securityException) 
                { 

                    if (memberAccessFlag && securityException.PermissionType.Equals(typeof(ReflectionPermission))) 
                    {
                        classContract.RequiresMemberAccessForRead(securityException);
                    }
                    else 
                    {
                        throw; 
                    } 
                }
                InitArgs(); 
                DemandSerializationFormatterPermission(classContract);
                DemandMemberAccessPermission(memberAccessFlag);
                CreateObject(classContract);
                ilg.Call(contextArg, XmlFormatGeneratorStatics.AddNewObjectMethod, objectLocal); 
                InvokeOnDeserializing(classContract);
                if (classContract.IsISerializable) 
                    ReadISerializable(classContract); 
                else
                    ReadClass(classContract); 
                if (Globals.TypeOfIDeserializationCallback.IsAssignableFrom(classContract.UnderlyingType))
                    ilg.Call(objectLocal, JsonFormatGeneratorStatics.OnDeserializationMethod, null);
                InvokeOnDeserialized(classContract);
                if (!InvokeFactoryMethod(classContract)) 
                {
                    ilg.Load(objectLocal); 
                    // Do a conversion back from DateTimeOffsetAdapter to DateTimeOffset after deserialization. 
                    // DateTimeOffsetAdapter is used here for deserialization purposes to bypass the ISerializable implementation
                    // on DateTimeOffset; which does not work in partial trust. 

                    if (classContract.UnderlyingType == Globals.TypeOfDateTimeOffsetAdapter)
                    {
                        ilg.ConvertValue(objectLocal.LocalType, Globals.TypeOfDateTimeOffsetAdapter); 
                        ilg.Call(XmlFormatGeneratorStatics.GetDateTimeOffsetMethod);
                        ilg.ConvertValue(Globals.TypeOfDateTimeOffset, ilg.CurrentMethod.ReturnType); 
                    } 
                    else
                    { 
                        ilg.ConvertValue(objectLocal.LocalType, ilg.CurrentMethod.ReturnType);
                    }
                }
                return (JsonFormatClassReaderDelegate)ilg.EndMethod(); 
            }
 
            static bool RequiresJsonMemberAccessForRead(Type underlyingType) 
            {
                return !JsonDataContract.IsTypeVisibleInJsonSerializationModule(underlyingType); 
            }

            public JsonFormatCollectionReaderDelegate GenerateCollectionReader(CollectionDataContract collectionContract)
            { 
                ilg = GenerateCollectionReaderHelper(collectionContract, false /*isGetOnlyCollection*/);
                ReadCollection(collectionContract); 
                ilg.Load(objectLocal); 
                ilg.ConvertValue(objectLocal.LocalType, ilg.CurrentMethod.ReturnType);
                return (JsonFormatCollectionReaderDelegate)ilg.EndMethod(); 
            }

            public JsonFormatGetOnlyCollectionReaderDelegate GenerateGetOnlyCollectionReader(CollectionDataContract collectionContract)
            { 
                ilg = GenerateCollectionReaderHelper(collectionContract, true /*isGetOnlyCollection*/);
                ReadGetOnlyCollection(collectionContract); 
                return (JsonFormatGetOnlyCollectionReaderDelegate)ilg.EndMethod(); 
            }
 
            CodeGenerator GenerateCollectionReaderHelper(CollectionDataContract collectionContract, bool isGetOnlyCollection)
            {
                ilg = new CodeGenerator();
                bool memberAccessFlag = collectionContract.RequiresMemberAccessForRead(null); 
                try
                { 
                    if (isGetOnlyCollection) 
                    {
                        BeginMethod(ilg, "Read" + collectionContract.StableName.Name + "FromJson" + "IsGetOnly", typeof(JsonFormatGetOnlyCollectionReaderDelegate), memberAccessFlag); 
                    }
                    else
                    {
                        BeginMethod(ilg, "Read" + collectionContract.StableName.Name + "FromJson", typeof(JsonFormatCollectionReaderDelegate), memberAccessFlag); 
                    }
                } 
                catch (SecurityException securityException) 
                {
                    if (memberAccessFlag && securityException.PermissionType.Equals(typeof(ReflectionPermission))) 
                    {
                        collectionContract.RequiresMemberAccessForRead(securityException);
                    }
                    else 
                    {
                        throw; 
                    } 
                }
                InitArgs(); 
                DemandMemberAccessPermission(memberAccessFlag);
                collectionContractArg = ilg.GetArg(4);
                return ilg;
            } 

            void BeginMethod(CodeGenerator ilg, string methodName, Type delegateType, bool allowPrivateMemberAccess) 
            { 
#if USE_REFEMIT
                ilg.BeginMethod(methodName, delegateType, allowPrivateMemberAccess); 
#else

                MethodInfo signature = delegateType.GetMethod("Invoke");
                ParameterInfo[] parameters = signature.GetParameters(); 
                Type[] paramTypes = new Type[parameters.Length];
                for (int i = 0; i < parameters.Length; i++) 
                    paramTypes[i] = parameters[i].ParameterType; 

                DynamicMethod dynamicMethod = new DynamicMethod(methodName, signature.ReturnType, paramTypes, typeof(JsonFormatReaderGenerator).Module, allowPrivateMemberAccess); 
                ilg.BeginMethod(dynamicMethod, delegateType, methodName, paramTypes, allowPrivateMemberAccess);
#endif
            }
 
            void InitArgs()
            { 
                xmlReaderArg = ilg.GetArg(0); 
                contextArg = ilg.GetArg(1);
                emptyDictionaryStringArg = ilg.GetArg(2); 
                memberNamesArg = ilg.GetArg(3);
            }

            void DemandMemberAccessPermission(bool memberAccessFlag) 
            {
                if (memberAccessFlag) 
                { 
                    ilg.Call(contextArg, XmlFormatGeneratorStatics.DemandMemberAccessPermissionMethod);
                } 
            }

            void DemandSerializationFormatterPermission(ClassDataContract classContract)
            { 
                if (!classContract.HasDataContract && !classContract.IsNonAttributedType)
                { 
                    ilg.Call(contextArg, XmlFormatGeneratorStatics.DemandSerializationFormatterPermissionMethod); 
                }
            } 


            void CreateObject(ClassDataContract classContract)
            { 
                Type type = objectType = classContract.UnderlyingType;
                if (type.IsValueType && !classContract.IsNonAttributedType) 
                    type = Globals.TypeOfValueType; 

                objectLocal = ilg.DeclareLocal(type, "objectDeserialized"); 

                if (classContract.UnderlyingType == Globals.TypeOfDBNull)
                {
                    ilg.LoadMember(Globals.TypeOfDBNull.GetField("Value")); 
                    ilg.Stloc(objectLocal);
                } 
                else if (classContract.IsNonAttributedType) 
                {
                    if (type.IsValueType) 
                    {
                        ilg.Ldloca(objectLocal);
                        ilg.InitObj(type);
                    } 
                    else
                    { 
                        ilg.New(classContract.GetNonAttributedTypeConstructor()); 
                        ilg.Stloc(objectLocal);
                    } 
                }
                else
                {
                    ilg.Call(null, JsonFormatGeneratorStatics.GetUninitializedObjectMethod, DataContract.GetIdForInitialization(classContract)); 
                    ilg.ConvertValue(Globals.TypeOfObject, type);
                    ilg.Stloc(objectLocal); 
                } 
            }
 
            void InvokeOnDeserializing(ClassDataContract classContract)
            {
                if (classContract.BaseContract != null)
                    InvokeOnDeserializing(classContract.BaseContract); 
                if (classContract.OnDeserializing != null)
                { 
                    ilg.LoadAddress(objectLocal); 
                    ilg.ConvertAddress(objectLocal.LocalType, objectType);
                    ilg.Load(contextArg); 
                    ilg.LoadMember(XmlFormatGeneratorStatics.GetStreamingContextMethod);
                    ilg.Call(classContract.OnDeserializing);
                }
            } 

            void InvokeOnDeserialized(ClassDataContract classContract) 
            { 
                if (classContract.BaseContract != null)
                    InvokeOnDeserialized(classContract.BaseContract); 
                if (classContract.OnDeserialized != null)
                {
                    ilg.LoadAddress(objectLocal);
                    ilg.ConvertAddress(objectLocal.LocalType, objectType); 
                    ilg.Load(contextArg);
                    ilg.LoadMember(XmlFormatGeneratorStatics.GetStreamingContextMethod); 
                    ilg.Call(classContract.OnDeserialized); 
                }
            } 

            bool HasFactoryMethod(ClassDataContract classContract)
            {
                return Globals.TypeOfIObjectReference.IsAssignableFrom(classContract.UnderlyingType); 
            }
 
            bool InvokeFactoryMethod(ClassDataContract classContract) 
            {
                if (HasFactoryMethod(classContract)) 
                {
                    ilg.Load(contextArg);
                    ilg.LoadAddress(objectLocal);
                    ilg.ConvertAddress(objectLocal.LocalType, Globals.TypeOfIObjectReference); 
                    ilg.Load(Globals.NewObjectId);
                    ilg.Call(XmlFormatGeneratorStatics.GetRealObjectMethod); 
                    ilg.ConvertValue(Globals.TypeOfObject, ilg.CurrentMethod.ReturnType); 
                    return true;
                } 
                return false;
            }

            void ReadClass(ClassDataContract classContract) 
            {
                if (classContract.HasExtensionData) 
                { 
                    LocalBuilder extensionDataLocal = ilg.DeclareLocal(Globals.TypeOfExtensionDataObject, "extensionData");
                    ilg.New(JsonFormatGeneratorStatics.ExtensionDataObjectCtor); 
                    ilg.Store(extensionDataLocal);
                    ReadMembers(classContract, extensionDataLocal);

                    ClassDataContract currentContract = classContract; 
                    while (currentContract != null)
                    { 
                        MethodInfo extensionDataSetMethod = currentContract.ExtensionDataSetMethod; 
                        if (extensionDataSetMethod != null)
                            ilg.Call(objectLocal, extensionDataSetMethod, extensionDataLocal); 
                        currentContract = currentContract.BaseContract;
                    }
                }
                else 
                    ReadMembers(classContract, null /*extensionDataLocal*/);
            } 
 
            void ReadMembers(ClassDataContract classContract, LocalBuilder extensionDataLocal)
            { 
                int memberCount = classContract.MemberNames.Length;
                ilg.Call(contextArg, XmlFormatGeneratorStatics.IncrementItemCountMethod, memberCount);

                BitFlagsGenerator expectedElements = new BitFlagsGenerator(memberCount, ilg, classContract.UnderlyingType.Name + "_ExpectedElements"); 
                byte[] requiredElements = new byte[expectedElements.GetLocalCount()];
                SetRequiredElements(classContract, requiredElements); 
                SetExpectedElements(expectedElements, 0 /*startIndex*/); 

                LocalBuilder memberIndexLocal = ilg.DeclareLocal(Globals.TypeOfInt, "memberIndex", -1); 
                Label throwDuplicateMemberLabel = ilg.DefineLabel();
                Label throwMissingRequiredMembersLabel = ilg.DefineLabel();

                object forReadElements = ilg.For(null, null, null); 
                ilg.Call(null, XmlFormatGeneratorStatics.MoveToNextElementMethod, xmlReaderArg);
                ilg.IfFalseBreak(forReadElements); 
                ilg.Call(contextArg, JsonFormatGeneratorStatics.GetJsonMemberIndexMethod, xmlReaderArg, memberNamesArg, memberIndexLocal, extensionDataLocal); 
                Label[] memberLabels = ilg.Switch(memberCount);
                ReadMembers(classContract, expectedElements, memberLabels, throwDuplicateMemberLabel, memberIndexLocal); 
                ilg.EndSwitch();
                ilg.EndFor();
                CheckRequiredElements(expectedElements, requiredElements, throwMissingRequiredMembersLabel);
                Label endOfTypeLabel = ilg.DefineLabel(); 
                ilg.Br(endOfTypeLabel);
 
                ilg.MarkLabel(throwDuplicateMemberLabel); 
                ilg.Call(null, JsonFormatGeneratorStatics.ThrowDuplicateMemberExceptionMethod, objectLocal, memberNamesArg, memberIndexLocal);
 
                ilg.MarkLabel(throwMissingRequiredMembersLabel);
                ilg.Load(objectLocal);
                ilg.ConvertValue(objectLocal.LocalType, Globals.TypeOfObject);
                ilg.Load(memberNamesArg); 
                expectedElements.LoadArray();
                LoadArray(requiredElements, "requiredElements"); 
                ilg.Call(JsonFormatGeneratorStatics.ThrowMissingRequiredMembersMethod); 

                ilg.MarkLabel(endOfTypeLabel); 
            }

            int ReadMembers(ClassDataContract classContract, BitFlagsGenerator expectedElements,
                Label[] memberLabels, Label throwDuplicateMemberLabel, LocalBuilder memberIndexLocal) 
            {
                int memberCount = (classContract.BaseContract == null) ? 0 : 
                    ReadMembers(classContract.BaseContract, expectedElements, memberLabels, throwDuplicateMemberLabel, memberIndexLocal); 

                for (int i = 0; i < classContract.Members.Count; i++, memberCount++) 
                {
                    DataMember dataMember = classContract.Members[i];
                    Type memberType = dataMember.MemberType;
                    ilg.Case(memberLabels[memberCount], dataMember.Name); 
                    ilg.Set(memberIndexLocal, memberCount);
                    expectedElements.Load(memberCount); 
                    ilg.Brfalse(throwDuplicateMemberLabel); 
                    LocalBuilder value = null;
                    if (dataMember.IsGetOnlyCollection) 
                    {
                        ilg.LoadAddress(objectLocal);
                        ilg.LoadMember(dataMember.MemberInfo);
                        value = ilg.DeclareLocal(memberType, dataMember.Name + "Value"); 
                        ilg.Stloc(value);
                        ilg.Call(contextArg, XmlFormatGeneratorStatics.StoreCollectionMemberInfoMethod, value); 
                        ReadValue(memberType, dataMember.Name); 
                    }
                    else 
                    {
                        value = ReadValue(memberType, dataMember.Name);
                        ilg.LoadAddress(objectLocal);
                        ilg.ConvertAddress(objectLocal.LocalType, objectType); 
                        ilg.Ldloc(value);
                        ilg.StoreMember(dataMember.MemberInfo); 
                    } 
                    ResetExpectedElements(expectedElements, memberCount);
                    ilg.EndCase(); 
                }
                return memberCount;
            }
 
            void CheckRequiredElements(BitFlagsGenerator expectedElements, byte[] requiredElements, Label throwMissingRequiredMembersLabel)
            { 
                for (int i = 0; i < requiredElements.Length; i++) 
                {
                    ilg.Load(expectedElements.GetLocal(i)); 
                    ilg.Load(requiredElements[i]);
                    ilg.And();
                    ilg.Load(0);
                    ilg.Ceq(); 
                    ilg.Brfalse(throwMissingRequiredMembersLabel);
                } 
            } 

            void LoadArray(byte[] array, string name) 
            {
                LocalBuilder localArray = ilg.DeclareLocal(Globals.TypeOfByteArray, name);
                ilg.NewArray(typeof(byte), array.Length);
                ilg.Store(localArray); 
                for (int i = 0; i < array.Length; i++)
                { 
                    ilg.StoreArrayElement(localArray, i, array[i]); 
                }
                ilg.Load(localArray); 
            }

            int SetRequiredElements(ClassDataContract contract, byte[] requiredElements)
            { 
                int memberCount = (contract.BaseContract == null) ? 0 :
                    SetRequiredElements(contract.BaseContract, requiredElements); 
                List members = contract.Members; 
                for (int i = 0; i < members.Count; i++, memberCount++)
                { 
                    if (members[i].IsRequired)
                    {
                        BitFlagsGenerator.SetBit(requiredElements, memberCount);
                    } 
                }
                return memberCount; 
            } 

            void SetExpectedElements(BitFlagsGenerator expectedElements, int startIndex) 
            {
                int memberCount = expectedElements.GetBitCount();
                for (int i = startIndex; i < memberCount; i++)
                { 
                    expectedElements.Store(i, true);
                } 
            } 

            void ResetExpectedElements(BitFlagsGenerator expectedElements, int index) 
            {
                expectedElements.Store(index, false);
            }
 
            void ReadISerializable(ClassDataContract classContract)
            { 
                ConstructorInfo ctor = classContract.UnderlyingType.GetConstructor(Globals.ScanAllMembers, null, JsonFormatGeneratorStatics.SerInfoCtorArgs, null); 
                if (ctor == null)
                    throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.SerializationInfo_ConstructorNotFound, DataContract.GetClrTypeFullName(classContract.UnderlyingType)))); 
                ilg.LoadAddress(objectLocal);
                ilg.ConvertAddress(objectLocal.LocalType, objectType);
                ilg.Call(contextArg, XmlFormatGeneratorStatics.ReadSerializationInfoMethod, xmlReaderArg, classContract.UnderlyingType);
                ilg.Load(contextArg); 
                ilg.LoadMember(XmlFormatGeneratorStatics.GetStreamingContextMethod);
                ilg.Call(ctor); 
            } 

            LocalBuilder ReadValue(Type type, string name) 
            {
                LocalBuilder value = ilg.DeclareLocal(type, "valueRead");
                LocalBuilder nullableValue = null;
                int nullables = 0; 
                while (type.IsGenericType && type.GetGenericTypeDefinition() == Globals.TypeOfNullable)
                { 
                    nullables++; 
                    type = type.GetGenericArguments()[0];
                } 

                PrimitiveDataContract primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract(type);
                if ((primitiveContract != null && primitiveContract.UnderlyingType != Globals.TypeOfObject) || nullables != 0 || type.IsValueType)
                { 
                    LocalBuilder objectId = ilg.DeclareLocal(Globals.TypeOfString, "objectIdRead");
                    ilg.Call(contextArg, XmlFormatGeneratorStatics.ReadAttributesMethod, xmlReaderArg); 
                    ilg.Call(contextArg, XmlFormatGeneratorStatics.ReadIfNullOrRefMethod, xmlReaderArg, type, DataContract.IsTypeSerializable(type)); 
                    ilg.Stloc(objectId);
                    // Deserialize null 
                    ilg.If(objectId, Cmp.EqualTo, Globals.NullObjectId);
                    if (nullables != 0)
                    {
                        ilg.LoadAddress(value); 
                        ilg.InitObj(value.LocalType);
                    } 
                    else if (type.IsValueType) 
                        ThrowValidationException(SR.GetString(SR.ValueTypeCannotBeNull, DataContract.GetClrTypeFullName(type)));
                    else 
                    {
                        ilg.Load(null);
                        ilg.Stloc(value);
                    } 

                    // Deserialize value 
 
                    // Compare against Globals.NewObjectId, which is set to string.Empty
                    ilg.ElseIfIsEmptyString(objectId); 
                    ilg.Call(contextArg, XmlFormatGeneratorStatics.GetObjectIdMethod);
                    ilg.Stloc(objectId);
                    if (type.IsValueType)
                    { 
                        ilg.IfNotIsEmptyString(objectId);
                        ThrowValidationException(SR.GetString(SR.ValueTypeCannotHaveId, DataContract.GetClrTypeFullName(type))); 
                        ilg.EndIf(); 
                    }
                    if (nullables != 0) 
                    {
                        nullableValue = value;
                        value = ilg.DeclareLocal(type, "innerValueRead");
                    } 

                    if (primitiveContract != null && primitiveContract.UnderlyingType != Globals.TypeOfObject) 
                    { 
                        ilg.Call(xmlReaderArg, primitiveContract.XmlFormatReaderMethod);
                        ilg.Stloc(value); 
                        if (!type.IsValueType)
                            ilg.Call(contextArg, XmlFormatGeneratorStatics.AddNewObjectMethod, value);
                    }
                    else 
                    {
                        InternalDeserialize(value, type, name); 
                    } 
                    // Deserialize ref
                    ilg.Else(); 
                    if (type.IsValueType)
                        ThrowValidationException(SR.GetString(SR.ValueTypeCannotHaveRef, DataContract.GetClrTypeFullName(type)));
                    else
                    { 
                        ilg.Call(contextArg, XmlFormatGeneratorStatics.GetExistingObjectMethod, objectId, type, name, string.Empty);
                        ilg.ConvertValue(Globals.TypeOfObject, type); 
                        ilg.Stloc(value); 
                    }
                    ilg.EndIf(); 

                    if (nullableValue != null)
                    {
                        ilg.If(objectId, Cmp.NotEqualTo, Globals.NullObjectId); 
                        WrapNullableObject(value, nullableValue, nullables);
                        ilg.EndIf(); 
                        value = nullableValue; 
                    }
                } 
                else
                {
                    InternalDeserialize(value, type, name);
                } 

                return value; 
            } 

            void InternalDeserialize(LocalBuilder value, Type type, string name) 
            {
                ilg.Load(contextArg);
                ilg.Load(xmlReaderArg);
                Type declaredType = type.IsPointer ? Globals.TypeOfReflectionPointer : type; 
                ilg.Load(DataContract.GetId(declaredType.TypeHandle));
                ilg.Ldtoken(declaredType); 
                ilg.Load(name); 
                // Empty namespace
                ilg.Load(string.Empty); 
                ilg.Call(XmlFormatGeneratorStatics.InternalDeserializeMethod);

                if (type.IsPointer)
                    ilg.Call(JsonFormatGeneratorStatics.UnboxPointer); 
                else
                    ilg.ConvertValue(Globals.TypeOfObject, type); 
                ilg.Stloc(value); 
            }
 
            void WrapNullableObject(LocalBuilder innerValue, LocalBuilder outerValue, int nullables)
            {
                Type innerType = innerValue.LocalType, outerType = outerValue.LocalType;
                ilg.LoadAddress(outerValue); 
                ilg.Load(innerValue);
                for (int i = 1; i < nullables; i++) 
                { 
                    Type type = Globals.TypeOfNullable.MakeGenericType(innerType);
                    ilg.New(type.GetConstructor(new Type[] { innerType })); 
                    innerType = type;
                }
                ilg.Call(outerType.GetConstructor(new Type[] { innerType }));
            } 

            void ReadCollection(CollectionDataContract collectionContract) 
            { 
                Type type = collectionContract.UnderlyingType;
                Type itemType = collectionContract.ItemType; 
                bool isArray = (collectionContract.Kind == CollectionKind.Array);
                ConstructorInfo constructor = collectionContract.Constructor;
                if (type.IsInterface)
                { 
                    switch (collectionContract.Kind)
                    { 
                        case CollectionKind.GenericDictionary: 
                            type = Globals.TypeOfDictionaryGeneric.MakeGenericType(itemType.GetGenericArguments());
                            constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Globals.EmptyTypeArray, null); 
                            break;
                        case CollectionKind.Dictionary:
                            type = Globals.TypeOfHashtable;
                            constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Globals.EmptyTypeArray, null); 
                            break;
                        case CollectionKind.Collection: 
                        case CollectionKind.GenericCollection: 
                        case CollectionKind.Enumerable:
                        case CollectionKind.GenericEnumerable: 
                        case CollectionKind.List:
                        case CollectionKind.GenericList:
                            type = itemType.MakeArrayType();
                            isArray = true; 
                            break;
                    } 
                } 

                objectLocal = ilg.DeclareLocal(type, "objectDeserialized"); 
                if (!isArray)
                {
                    if (type.IsValueType)
                    { 
                        ilg.Ldloca(objectLocal);
                        ilg.InitObj(type); 
                    } 
                    else
                    { 
                        ilg.New(constructor);
                        ilg.Stloc(objectLocal);
                        ilg.Call(contextArg, XmlFormatGeneratorStatics.AddNewObjectMethod, objectLocal);
                    } 
                }
 
                LocalBuilder size = ilg.DeclareLocal(Globals.TypeOfInt, "arraySize"); 
                ilg.Call(contextArg, XmlFormatGeneratorStatics.GetArraySizeMethod);
                ilg.Stloc(size); 

                LocalBuilder objectId = ilg.DeclareLocal(Globals.TypeOfString, "objectIdRead");
                ilg.Call(contextArg, XmlFormatGeneratorStatics.GetObjectIdMethod);
                ilg.Stloc(objectId); 

                bool canReadPrimitiveArray = false; 
                if (isArray && TryReadPrimitiveArray(itemType, size)) 
                {
                    canReadPrimitiveArray = true; 
                    ilg.IfNot();
                }

                ilg.If(size, Cmp.EqualTo, -1); 

                LocalBuilder growingCollection = null; 
                if (isArray) 
                {
                    growingCollection = ilg.DeclareLocal(type, "growingCollection"); 
                    ilg.NewArray(itemType, 32);
                    ilg.Stloc(growingCollection);
                }
                LocalBuilder i = ilg.DeclareLocal(Globals.TypeOfInt, "i"); 
                object forLoop = ilg.For(i, 0, Int32.MaxValue);
                // Empty namespace 
                IsStartElement(memberNamesArg, emptyDictionaryStringArg); 
                ilg.If();
                ilg.Call(contextArg, XmlFormatGeneratorStatics.IncrementItemCountMethod, 1); 
                LocalBuilder value = ReadCollectionItem(collectionContract, itemType);
                if (isArray)
                {
                    MethodInfo ensureArraySizeMethod = XmlFormatGeneratorStatics.EnsureArraySizeMethod.MakeGenericMethod(itemType); 
                    ilg.Call(null, ensureArraySizeMethod, growingCollection, i);
                    ilg.Stloc(growingCollection); 
                    ilg.StoreArrayElement(growingCollection, i, value); 
                }
                else 
                    StoreCollectionValue(objectLocal, value, collectionContract);
                ilg.Else();
                IsEndElement();
                ilg.If(); 
                ilg.Break(forLoop);
                ilg.Else(); 
                HandleUnexpectedItemInCollection(i); 
                ilg.EndIf();
                ilg.EndIf(); 

                ilg.EndFor();
                if (isArray)
                { 
                    MethodInfo trimArraySizeMethod = XmlFormatGeneratorStatics.TrimArraySizeMethod.MakeGenericMethod(itemType);
                    ilg.Call(null, trimArraySizeMethod, growingCollection, i); 
                    ilg.Stloc(objectLocal); 
                    ilg.Call(contextArg, XmlFormatGeneratorStatics.AddNewObjectWithIdMethod, objectId, objectLocal);
                } 
                ilg.Else();

                ilg.Call(contextArg, XmlFormatGeneratorStatics.IncrementItemCountMethod, size);
                if (isArray) 
                {
                    ilg.NewArray(itemType, size); 
                    ilg.Stloc(objectLocal); 
                    ilg.Call(contextArg, XmlFormatGeneratorStatics.AddNewObjectMethod, objectLocal);
                } 
                LocalBuilder j = ilg.DeclareLocal(Globals.TypeOfInt, "j");
                ilg.For(j, 0, size);
                // Empty namespace
                IsStartElement(memberNamesArg, emptyDictionaryStringArg); 
                ilg.If();
                LocalBuilder itemValue = ReadCollectionItem(collectionContract, itemType); 
                if (isArray) 
                    ilg.StoreArrayElement(objectLocal, j, itemValue);
                else 
                    StoreCollectionValue(objectLocal, itemValue, collectionContract);
                ilg.Else();
                HandleUnexpectedItemInCollection(j);
                ilg.EndIf(); 
                ilg.EndFor();
                // Empty namespace 
                ilg.Call(contextArg, XmlFormatGeneratorStatics.CheckEndOfArrayMethod, xmlReaderArg, size, memberNamesArg, emptyDictionaryStringArg); 
                ilg.EndIf();
 
                if (canReadPrimitiveArray)
                {
                    ilg.Else();
                    ilg.Call(contextArg, XmlFormatGeneratorStatics.AddNewObjectWithIdMethod, objectId, objectLocal); 
                    ilg.EndIf();
                } 
            } 

            void ReadGetOnlyCollection(CollectionDataContract collectionContract) 
            {
                Type type = collectionContract.UnderlyingType;
                Type itemType = collectionContract.ItemType;
                bool isArray = (collectionContract.Kind == CollectionKind.Array); 

                objectLocal = ilg.DeclareLocal(type, "objectDeserialized"); 
                ilg.Load(contextArg); 
                ilg.LoadMember(XmlFormatGeneratorStatics.GetCollectionMemberMethod);
                ilg.ConvertValue(Globals.TypeOfObject, type); 
                ilg.Stloc(objectLocal);

                //check that items are actually going to be deserialized into the collection
                IsStartElement(memberNamesArg, emptyDictionaryStringArg); 
                ilg.If();
                ilg.If(objectLocal, Cmp.EqualTo, null); 
                ilg.Call(null, XmlFormatGeneratorStatics.ThrowNullValueReturnedForGetOnlyCollectionExceptionMethod, type); 

                ilg.Else(); 
                LocalBuilder size = ilg.DeclareLocal(Globals.TypeOfInt, "arraySize");
                if (isArray)
                {
                    ilg.Load(objectLocal); 
                    ilg.Call(XmlFormatGeneratorStatics.GetArrayLengthMethod);
                    ilg.Stloc(size); 
                } 

                LocalBuilder i = ilg.DeclareLocal(Globals.TypeOfInt, "i"); 
                object forLoop = ilg.For(i, 0, Int32.MaxValue);
                IsStartElement(memberNamesArg, emptyDictionaryStringArg);
                ilg.If();
                ilg.Call(contextArg, XmlFormatGeneratorStatics.IncrementItemCountMethod, 1); 
                LocalBuilder value = ReadCollectionItem(collectionContract, itemType);
                if (isArray) 
                { 
                    ilg.If(size, Cmp.EqualTo, i);
                    ilg.Call(null, XmlFormatGeneratorStatics.ThrowArrayExceededSizeExceptionMethod, size, type); 
                    ilg.Else();
                    ilg.StoreArrayElement(objectLocal, i, value);
                    ilg.EndIf();
                } 
                else
                    StoreCollectionValue(objectLocal, value, collectionContract); 
                ilg.Else(); 
                IsEndElement();
                ilg.If(); 
                ilg.Break(forLoop);
                ilg.Else();
                HandleUnexpectedItemInCollection(i);
                ilg.EndIf(); 
                ilg.EndIf();
                ilg.EndFor(); 
                ilg.Call(contextArg, XmlFormatGeneratorStatics.CheckEndOfArrayMethod, xmlReaderArg, size, memberNamesArg, emptyDictionaryStringArg); 

                ilg.EndIf(); 
                ilg.EndIf();
            }

            bool TryReadPrimitiveArray(Type itemType, LocalBuilder size) 
            {
                PrimitiveDataContract primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract(itemType); 
                if (primitiveContract == null) 
                    return false;
 
                string readArrayMethod = null;
                switch (Type.GetTypeCode(itemType))
                {
                    case TypeCode.Boolean: 
                        readArrayMethod = "TryReadBooleanArray";
                        break; 
                    case TypeCode.Decimal: 
                        readArrayMethod = "TryReadDecimalArray";
                        break; 
                    case TypeCode.Int32:
                        readArrayMethod = "TryReadInt32Array";
                        break;
                    case TypeCode.Int64: 
                        readArrayMethod = "TryReadInt64Array";
                        break; 
                    case TypeCode.Single: 
                        readArrayMethod = "TryReadSingleArray";
                        break; 
                    case TypeCode.Double:
                        readArrayMethod = "TryReadDoubleArray";
                        break;
                    case TypeCode.DateTime: 
                        readArrayMethod = "TryReadJsonDateTimeArray";
                        break; 
                    default: 
                        break;
                } 
                if (readArrayMethod != null)
                {
                    ilg.Load(xmlReaderArg);
                    ilg.ConvertValue(typeof(XmlReaderDelegator), typeof(JsonReaderDelegator)); 
                    ilg.Load(contextArg);
                    ilg.Load(memberNamesArg); 
                    // Empty namespace 
                    ilg.Load(emptyDictionaryStringArg);
                    ilg.Load(size); 
                    ilg.Ldloca(objectLocal);
                    ilg.Call(typeof(JsonReaderDelegator).GetMethod(readArrayMethod, Globals.ScanAllMembers));
                    return true;
                } 
                return false;
            } 
 
            LocalBuilder ReadCollectionItem(CollectionDataContract collectionContract, Type itemType)
            { 
                if (collectionContract.Kind == CollectionKind.Dictionary || collectionContract.Kind == CollectionKind.GenericDictionary)
                {
                    ilg.Call(contextArg, XmlFormatGeneratorStatics.ResetAttributesMethod);
                    LocalBuilder value = ilg.DeclareLocal(itemType, "valueRead"); 
                    ilg.Load(collectionContractArg);
                    ilg.Call(JsonFormatGeneratorStatics.GetItemContractMethod); 
                    ilg.Call(JsonFormatGeneratorStatics.GetRevisedItemContractMethod); 
                    ilg.Load(xmlReaderArg);
                    ilg.Load(contextArg); 
                    ilg.Call(JsonFormatGeneratorStatics.ReadJsonValueMethod);
                    ilg.ConvertValue(Globals.TypeOfObject, itemType);
                    ilg.Stloc(value);
                    return value; 
                }
                else 
                { 
                    return ReadValue(itemType, JsonGlobals.itemString);
                } 
            }

            void StoreCollectionValue(LocalBuilder collection, LocalBuilder value, CollectionDataContract collectionContract)
            { 
                if (collectionContract.Kind == CollectionKind.GenericDictionary || collectionContract.Kind == CollectionKind.Dictionary)
                { 
                    ClassDataContract keyValuePairContract = DataContract.GetDataContract(value.LocalType) as ClassDataContract; 
                    if (keyValuePairContract == null)
                    { 
                        Fx.Assert("Failed to create contract for KeyValuePair type");
                    }
                    DataMember keyMember = keyValuePairContract.Members[0];
                    DataMember valueMember = keyValuePairContract.Members[1]; 
                    LocalBuilder pairKey = ilg.DeclareLocal(keyMember.MemberType, keyMember.Name);
                    LocalBuilder pairValue = ilg.DeclareLocal(valueMember.MemberType, valueMember.Name); 
                    ilg.LoadAddress(value); 
                    ilg.LoadMember(keyMember.MemberInfo);
                    ilg.Stloc(pairKey); 
                    ilg.LoadAddress(value);
                    ilg.LoadMember(valueMember.MemberInfo);
                    ilg.Stloc(pairValue);
 
                    ilg.Call(collection, collectionContract.AddMethod, pairKey, pairValue);
                    if (collectionContract.AddMethod.ReturnType != Globals.TypeOfVoid) 
                        ilg.Pop(); 
                }
                else 
                {
                    ilg.Call(collection, collectionContract.AddMethod, value);
                    if (collectionContract.AddMethod.ReturnType != Globals.TypeOfVoid)
                        ilg.Pop(); 
                }
            } 
 
            void HandleUnexpectedItemInCollection(LocalBuilder iterator)
            { 
                IsStartElement();
                ilg.If();
                ilg.Call(contextArg, XmlFormatGeneratorStatics.SkipUnknownElementMethod, xmlReaderArg);
                ilg.Dec(iterator); 
                ilg.Else();
                ThrowUnexpectedStateException(XmlNodeType.Element); 
                ilg.EndIf(); 
            }
 
            void IsStartElement(ArgBuilder nameArg, ArgBuilder nsArg)
            {
                ilg.Call(xmlReaderArg, JsonFormatGeneratorStatics.IsStartElementMethod2, nameArg, nsArg);
            } 

            void IsStartElement() 
            { 
                ilg.Call(xmlReaderArg, JsonFormatGeneratorStatics.IsStartElementMethod0);
            } 

            void IsEndElement()
            {
                ilg.Load(xmlReaderArg); 
                ilg.LoadMember(JsonFormatGeneratorStatics.NodeTypeProperty);
                ilg.Load(XmlNodeType.EndElement); 
                ilg.Ceq(); 
            }
 
            void ThrowUnexpectedStateException(XmlNodeType expectedState)
            {
                ilg.Call(null, XmlFormatGeneratorStatics.CreateUnexpectedStateExceptionMethod, expectedState, xmlReaderArg);
                ilg.Throw(); 
            }
 
            void ThrowValidationException(string msg, params object[] values) 
            {
                if (values != null && values.Length > 0) 
                    ilg.CallStringFormat(msg, values);
                else
                    ilg.Load(msg);
                ThrowValidationException(); 
            }
 
            void ThrowValidationException() 
            {
                ilg.New(JsonFormatGeneratorStatics.SerializationExceptionCtor); 
                ilg.Throw();
            }
        }
    } 
}
 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.


                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK