示例#1
0
            private void WriteCollection(CollectionDataContract collectionContract)
            {
                LocalBuilder itemName = _ilg.DeclareLocal(typeof(XmlDictionaryString), "itemName");

                _ilg.Load(_contextArg);
                _ilg.LoadMember(JsonFormatGeneratorStatics.CollectionItemNameProperty);
                _ilg.Store(itemName);

                if (collectionContract.Kind == CollectionKind.Array)
                {
                    Type         itemType = collectionContract.ItemType;
                    LocalBuilder i        = _ilg.DeclareLocal(Globals.TypeOfInt, "i");

                    _ilg.Call(_contextArg, XmlFormatGeneratorStatics.IncrementArrayCountMethod, _xmlWriterArg, _objectLocal);

                    if (!TryWritePrimitiveArray(collectionContract.UnderlyingType, itemType, _objectLocal, itemName))
                    {
                        WriteArrayAttribute();
                        _ilg.For(i, 0, _objectLocal);
                        if (!TryWritePrimitive(itemType, null /*value*/, null /*memberInfo*/, i /*arrayItemIndex*/, itemName, 0 /*nameIndex*/))
                        {
                            WriteStartElement(itemName, 0 /*nameIndex*/);
                            _ilg.LoadArrayElement(_objectLocal, i);
                            LocalBuilder memberValue = _ilg.DeclareLocal(itemType, "memberValue");
                            _ilg.Stloc(memberValue);
                            WriteValue(memberValue);
                            WriteEndElement();
                        }
                        _ilg.EndFor();
                    }
                }
                else
                {
                    MethodInfo incrementCollectionCountMethod = null;
                    switch (collectionContract.Kind)
                    {
                    case CollectionKind.Collection:
                    case CollectionKind.List:
                    case CollectionKind.Dictionary:
                        incrementCollectionCountMethod = XmlFormatGeneratorStatics.IncrementCollectionCountMethod;
                        break;

                    case CollectionKind.GenericCollection:
                    case CollectionKind.GenericList:
                        incrementCollectionCountMethod = XmlFormatGeneratorStatics.IncrementCollectionCountGenericMethod.MakeGenericMethod(collectionContract.ItemType);
                        break;

                    case CollectionKind.GenericDictionary:
                        incrementCollectionCountMethod = XmlFormatGeneratorStatics.IncrementCollectionCountGenericMethod.MakeGenericMethod(Globals.TypeOfKeyValuePair.MakeGenericType(collectionContract.ItemType.GetGenericArguments()));
                        break;
                    }
                    if (incrementCollectionCountMethod != null)
                    {
                        _ilg.Call(_contextArg, incrementCollectionCountMethod, _xmlWriterArg, _objectLocal);
                    }

                    bool   isDictionary = false, isGenericDictionary = false;
                    Type   enumeratorType = null;
                    Type[] keyValueTypes  = null;
                    if (collectionContract.Kind == CollectionKind.GenericDictionary)
                    {
                        isGenericDictionary = true;
                        keyValueTypes       = collectionContract.ItemType.GetGenericArguments();
                        enumeratorType      = Globals.TypeOfGenericDictionaryEnumerator.MakeGenericType(keyValueTypes);
                    }
                    else if (collectionContract.Kind == CollectionKind.Dictionary)
                    {
                        isDictionary   = true;
                        keyValueTypes  = new Type[] { Globals.TypeOfObject, Globals.TypeOfObject };
                        enumeratorType = Globals.TypeOfDictionaryEnumerator;
                    }
                    else
                    {
                        enumeratorType = collectionContract.GetEnumeratorMethod.ReturnType;
                    }
                    MethodInfo moveNextMethod   = enumeratorType.GetMethod(Globals.MoveNextMethodName, BindingFlags.Instance | BindingFlags.Public, Array.Empty <Type>());
                    MethodInfo getCurrentMethod = enumeratorType.GetMethod(Globals.GetCurrentMethodName, BindingFlags.Instance | BindingFlags.Public, Array.Empty <Type>());
                    if (moveNextMethod == null || getCurrentMethod == null)
                    {
                        if (enumeratorType.GetTypeInfo().IsInterface)
                        {
                            if (moveNextMethod == null)
                            {
                                moveNextMethod = JsonFormatGeneratorStatics.MoveNextMethod;
                            }
                            if (getCurrentMethod == null)
                            {
                                getCurrentMethod = JsonFormatGeneratorStatics.GetCurrentMethod;
                            }
                        }
                        else
                        {
                            Type           ienumeratorInterface = Globals.TypeOfIEnumerator;
                            CollectionKind kind = collectionContract.Kind;
                            if (kind == CollectionKind.GenericDictionary || kind == CollectionKind.GenericCollection || kind == CollectionKind.GenericEnumerable)
                            {
                                Type[] interfaceTypes = enumeratorType.GetInterfaces();
                                foreach (Type interfaceType in interfaceTypes)
                                {
                                    if (interfaceType.GetTypeInfo().IsGenericType &&
                                        interfaceType.GetGenericTypeDefinition() == Globals.TypeOfIEnumeratorGeneric &&
                                        interfaceType.GetGenericArguments()[0] == collectionContract.ItemType)
                                    {
                                        ienumeratorInterface = interfaceType;
                                        break;
                                    }
                                }
                            }
                            if (moveNextMethod == null)
                            {
                                moveNextMethod = CollectionDataContract.GetTargetMethodWithName(Globals.MoveNextMethodName, enumeratorType, ienumeratorInterface);
                            }
                            if (getCurrentMethod == null)
                            {
                                getCurrentMethod = CollectionDataContract.GetTargetMethodWithName(Globals.GetCurrentMethodName, enumeratorType, ienumeratorInterface);
                            }
                        }
                    }
                    Type         elementType  = getCurrentMethod.ReturnType;
                    LocalBuilder currentValue = _ilg.DeclareLocal(elementType, "currentValue");

                    LocalBuilder enumerator = _ilg.DeclareLocal(enumeratorType, "enumerator");
                    _ilg.Call(_objectLocal, collectionContract.GetEnumeratorMethod);
                    if (isDictionary)
                    {
                        ConstructorInfo dictEnumCtor = enumeratorType.GetConstructor(Globals.ScanAllMembers, new Type[] { Globals.TypeOfIDictionaryEnumerator });
                        _ilg.ConvertValue(collectionContract.GetEnumeratorMethod.ReturnType, Globals.TypeOfIDictionaryEnumerator);
                        _ilg.New(dictEnumCtor);
                    }
                    else if (isGenericDictionary)
                    {
                        Type            ctorParam    = Globals.TypeOfIEnumeratorGeneric.MakeGenericType(Globals.TypeOfKeyValuePair.MakeGenericType(keyValueTypes));
                        ConstructorInfo dictEnumCtor = enumeratorType.GetConstructor(Globals.ScanAllMembers, new Type[] { ctorParam });
                        _ilg.ConvertValue(collectionContract.GetEnumeratorMethod.ReturnType, ctorParam);
                        _ilg.New(dictEnumCtor);
                    }
                    _ilg.Stloc(enumerator);

                    bool canWriteSimpleDictionary = isDictionary || isGenericDictionary;
                    if (canWriteSimpleDictionary)
                    {
                        Type         genericDictionaryKeyValueType  = Globals.TypeOfKeyValue.MakeGenericType(keyValueTypes);
                        PropertyInfo genericDictionaryKeyProperty   = genericDictionaryKeyValueType.GetProperty(JsonGlobals.KeyString);
                        PropertyInfo genericDictionaryValueProperty = genericDictionaryKeyValueType.GetProperty(JsonGlobals.ValueString);

                        _ilg.Load(_contextArg);
                        _ilg.LoadMember(JsonFormatGeneratorStatics.UseSimpleDictionaryFormatWriteProperty);
                        _ilg.If();
                        WriteObjectAttribute();
                        LocalBuilder pairKey   = _ilg.DeclareLocal(Globals.TypeOfString, "key");
                        LocalBuilder pairValue = _ilg.DeclareLocal(keyValueTypes[1], "value");
                        _ilg.ForEach(currentValue, elementType, enumeratorType, enumerator, getCurrentMethod);

                        _ilg.LoadAddress(currentValue);
                        _ilg.LoadMember(genericDictionaryKeyProperty);
                        _ilg.ToString(keyValueTypes[0]);
                        _ilg.Stloc(pairKey);

                        _ilg.LoadAddress(currentValue);
                        _ilg.LoadMember(genericDictionaryValueProperty);
                        _ilg.Stloc(pairValue);

                        WriteStartElement(pairKey, 0 /*nameIndex*/);
                        WriteValue(pairValue);
                        WriteEndElement();

                        _ilg.EndForEach(moveNextMethod);
                        _ilg.Else();
                    }

                    WriteArrayAttribute();

                    _ilg.ForEach(currentValue, elementType, enumeratorType, enumerator, getCurrentMethod);
                    if (incrementCollectionCountMethod == null)
                    {
                        _ilg.Call(_contextArg, XmlFormatGeneratorStatics.IncrementItemCountMethod, 1);
                    }
                    if (!TryWritePrimitive(elementType, currentValue, null /*memberInfo*/, null /*arrayItemIndex*/, itemName, 0 /*nameIndex*/))
                    {
                        WriteStartElement(itemName, 0 /*nameIndex*/);

                        if (isGenericDictionary || isDictionary)
                        {
                            _ilg.Call(_dataContractArg, JsonFormatGeneratorStatics.GetItemContractMethod);
                            _ilg.Call(JsonFormatGeneratorStatics.GetRevisedItemContractMethod);
                            _ilg.Call(JsonFormatGeneratorStatics.GetJsonDataContractMethod);
                            _ilg.Load(_xmlWriterArg);
                            _ilg.Load(currentValue);
                            _ilg.ConvertValue(currentValue.LocalType, Globals.TypeOfObject);
                            _ilg.Load(_contextArg);
                            _ilg.Load(currentValue.LocalType);
                            _ilg.LoadMember(JsonFormatGeneratorStatics.TypeHandleProperty);
                            _ilg.Call(JsonFormatGeneratorStatics.WriteJsonValueMethod);
                        }
                        else
                        {
                            WriteValue(currentValue);
                        }
                        WriteEndElement();
                    }
                    _ilg.EndForEach(moveNextMethod);

                    if (canWriteSimpleDictionary)
                    {
                        _ilg.EndIf();
                    }
                }
            }
示例#2
0
            void WriteCollection(CollectionDataContract collectionContract)
            {
                LocalBuilder itemNamespace = ilg.DeclareLocal(typeof(XmlDictionaryString), "itemNamespace");

                ilg.Load(dataContractArg);
                ilg.LoadMember(XmlFormatGeneratorStatics.NamespaceProperty);
                ilg.Store(itemNamespace);

                LocalBuilder itemName = ilg.DeclareLocal(typeof(XmlDictionaryString), "itemName");

                ilg.Load(dataContractArg);
                ilg.LoadMember(XmlFormatGeneratorStatics.CollectionItemNameProperty);
                ilg.Store(itemName);

                if (collectionContract.ChildElementNamespace != null)
                {
                    ilg.Load(xmlWriterArg);
                    ilg.Load(dataContractArg);
                    ilg.LoadMember(XmlFormatGeneratorStatics.ChildElementNamespaceProperty);
                    ilg.Call(XmlFormatGeneratorStatics.WriteNamespaceDeclMethod);
                }

                if (collectionContract.Kind == CollectionKind.Array)
                {
                    Type         itemType = collectionContract.ItemType;
                    LocalBuilder i        = ilg.DeclareLocal(Globals.TypeOfInt, "i");

                    ilg.Call(contextArg, XmlFormatGeneratorStatics.IncrementArrayCountMethod, xmlWriterArg, objectLocal);

                    if (!TryWritePrimitiveArray(collectionContract.UnderlyingType, itemType, objectLocal, itemName, itemNamespace))
                    {
                        ilg.For(i, 0, objectLocal);
                        if (!TryWritePrimitive(itemType, null /*value*/, null /*memberInfo*/, i /*arrayItemIndex*/, itemNamespace, itemName, 0 /*nameIndex*/))
                        {
                            WriteStartElement(itemType, collectionContract.Namespace, itemNamespace, itemName, 0 /*nameIndex*/);
                            ilg.LoadArrayElement(objectLocal, i);
                            LocalBuilder memberValue = ilg.DeclareLocal(itemType, "memberValue");
                            ilg.Stloc(memberValue);
                            WriteValue(memberValue, false /*writeXsiType*/);
                            WriteEndElement();
                        }
                        ilg.EndFor();
                    }
                }
                else
                {
                    MethodInfo incrementCollectionCountMethod = null;
                    switch (collectionContract.Kind)
                    {
                    case CollectionKind.Collection:
                    case CollectionKind.List:
                    case CollectionKind.Dictionary:
                        incrementCollectionCountMethod = XmlFormatGeneratorStatics.IncrementCollectionCountMethod;
                        break;

                    case CollectionKind.GenericCollection:
                    case CollectionKind.GenericList:
                        incrementCollectionCountMethod = XmlFormatGeneratorStatics.IncrementCollectionCountGenericMethod.MakeGenericMethod(collectionContract.ItemType);
                        break;

                    case CollectionKind.GenericDictionary:
                        incrementCollectionCountMethod = XmlFormatGeneratorStatics.IncrementCollectionCountGenericMethod.MakeGenericMethod(Globals.TypeOfKeyValuePair.MakeGenericType(collectionContract.ItemType.GetGenericArguments()));
                        break;
                    }
                    if (incrementCollectionCountMethod != null)
                    {
                        ilg.Call(contextArg, incrementCollectionCountMethod, xmlWriterArg, objectLocal);
                    }

                    bool   isDictionary = false, isGenericDictionary = false;
                    Type   enumeratorType = null;
                    Type[] keyValueTypes  = null;
                    if (collectionContract.Kind == CollectionKind.GenericDictionary)
                    {
                        isGenericDictionary = true;
                        keyValueTypes       = collectionContract.ItemType.GetGenericArguments();
                        enumeratorType      = Globals.TypeOfGenericDictionaryEnumerator.MakeGenericType(keyValueTypes);
                    }
                    else if (collectionContract.Kind == CollectionKind.Dictionary)
                    {
                        isDictionary   = true;
                        keyValueTypes  = new Type[] { Globals.TypeOfObject, Globals.TypeOfObject };
                        enumeratorType = Globals.TypeOfDictionaryEnumerator;
                    }
                    else
                    {
                        enumeratorType = collectionContract.GetEnumeratorMethod.ReturnType;
                    }
                    MethodInfo moveNextMethod   = enumeratorType.GetMethod(Globals.MoveNextMethodName, BindingFlags.Instance | BindingFlags.Public, null, Globals.EmptyTypeArray, null);
                    MethodInfo getCurrentMethod = enumeratorType.GetMethod(Globals.GetCurrentMethodName, BindingFlags.Instance | BindingFlags.Public, null, Globals.EmptyTypeArray, null);
                    if (moveNextMethod == null || getCurrentMethod == null)
                    {
                        if (enumeratorType.IsInterface)
                        {
                            if (moveNextMethod == null)
                            {
                                moveNextMethod = XmlFormatGeneratorStatics.MoveNextMethod;
                            }
                            if (getCurrentMethod == null)
                            {
                                getCurrentMethod = XmlFormatGeneratorStatics.GetCurrentMethod;
                            }
                        }
                        else
                        {
                            Type           ienumeratorInterface = Globals.TypeOfIEnumerator;
                            CollectionKind kind = collectionContract.Kind;
                            if (kind == CollectionKind.GenericDictionary || kind == CollectionKind.GenericCollection || kind == CollectionKind.GenericEnumerable)
                            {
                                Type[] interfaceTypes = enumeratorType.GetInterfaces();
                                foreach (Type interfaceType in interfaceTypes)
                                {
                                    if (interfaceType.IsGenericType &&
                                        interfaceType.GetGenericTypeDefinition() == Globals.TypeOfIEnumeratorGeneric &&
                                        interfaceType.GetGenericArguments()[0] == collectionContract.ItemType)
                                    {
                                        ienumeratorInterface = interfaceType;
                                        break;
                                    }
                                }
                            }
                            if (moveNextMethod == null)
                            {
                                moveNextMethod = CollectionDataContract.GetTargetMethodWithName(Globals.MoveNextMethodName, enumeratorType, ienumeratorInterface);
                            }
                            if (getCurrentMethod == null)
                            {
                                getCurrentMethod = CollectionDataContract.GetTargetMethodWithName(Globals.GetCurrentMethodName, enumeratorType, ienumeratorInterface);
                            }
                        }
                    }
                    Type         elementType  = getCurrentMethod.ReturnType;
                    LocalBuilder currentValue = ilg.DeclareLocal(elementType, "currentValue");

                    LocalBuilder enumerator = ilg.DeclareLocal(enumeratorType, "enumerator");
                    ilg.Call(objectLocal, collectionContract.GetEnumeratorMethod);
                    if (isDictionary)
                    {
                        ilg.ConvertValue(collectionContract.GetEnumeratorMethod.ReturnType, Globals.TypeOfIDictionaryEnumerator);
                        ilg.New(XmlFormatGeneratorStatics.DictionaryEnumeratorCtor);
                    }
                    else if (isGenericDictionary)
                    {
                        Type            ctorParam    = Globals.TypeOfIEnumeratorGeneric.MakeGenericType(Globals.TypeOfKeyValuePair.MakeGenericType(keyValueTypes));
                        ConstructorInfo dictEnumCtor = enumeratorType.GetConstructor(Globals.ScanAllMembers, null, new Type[] { ctorParam }, null);
                        ilg.ConvertValue(collectionContract.GetEnumeratorMethod.ReturnType, ctorParam);
                        ilg.New(dictEnumCtor);
                    }
                    ilg.Stloc(enumerator);

                    ilg.ForEach(currentValue, elementType, enumeratorType, enumerator, getCurrentMethod);
                    if (incrementCollectionCountMethod == null)
                    {
                        ilg.Call(contextArg, XmlFormatGeneratorStatics.IncrementItemCountMethod, 1);
                    }
                    if (!TryWritePrimitive(elementType, currentValue, null /*memberInfo*/, null /*arrayItemIndex*/, itemNamespace, itemName, 0 /*nameIndex*/))
                    {
                        WriteStartElement(elementType, collectionContract.Namespace, itemNamespace, itemName, 0 /*nameIndex*/);

                        if (isGenericDictionary || isDictionary)
                        {
                            ilg.Call(dataContractArg, XmlFormatGeneratorStatics.GetItemContractMethod);
                            ilg.Load(xmlWriterArg);
                            ilg.Load(currentValue);
                            ilg.ConvertValue(currentValue.LocalType, Globals.TypeOfObject);
                            ilg.Load(contextArg);
                            ilg.Call(XmlFormatGeneratorStatics.WriteXmlValueMethod);
                        }
                        else
                        {
                            WriteValue(currentValue, false /*writeXsiType*/);
                        }
                        WriteEndElement();
                    }
                    ilg.EndForEach(moveNextMethod);
                }
            }
        void WriteCollection(CollectionDataContract collectionContract)
        {
            XmlDictionaryString itemName = context.CollectionItemName;

            if (collectionContract.Kind == CollectionKind.Array)
            {
                Type itemType = collectionContract.ItemType;
                int  i;

                // This check does not exist in the original dynamic code,
                // but there is no other way to check type mismatch.
                // CollectionSerialization.ArrayContract() shows that it is required.
                if (objLocal.GetType().GetElementType() != itemType)
                {
                    throw new InvalidCastException(string.Format("Cannot cast array of {0} to array of {1}", objLocal.GetType().GetElementType(), itemType));
                }

                context.IncrementArrayCount(writer, (Array)objLocal);

                if (!TryWritePrimitiveArray(collectionContract.UnderlyingType, itemType, () => objLocal, itemName))
                {
                    WriteArrayAttribute();
                    var arr = (Array)objLocal;
                    var idx = new int [1];
                    for (i = 0; i < arr.Length; i++)
                    {
                        if (!TryWritePrimitive(itemType, null, null, i, itemName, 0))
                        {
                            WriteStartElement(itemName, 0);
                            idx [0] = i;
                            var mbrVal = arr.GetValue(idx);
                            WriteValue(itemType, mbrVal);
                            WriteEndElement();
                        }
                    }
                }
            }
            else
            {
                // This check does not exist in the original dynamic code,
                // but there is no other way to check type mismatch.
                // CollectionSerialization.ArrayContract() shows that it is required.
                if (!collectionContract.UnderlyingType.IsAssignableFrom(objLocal.GetType()))
                {
                    throw new InvalidCastException(string.Format("Cannot cast {0} to {1}", objLocal.GetType(), collectionContract.UnderlyingType));
                }

                MethodInfo incrementCollectionCountMethod = null;
                switch (collectionContract.Kind)
                {
                case CollectionKind.Collection:
                case CollectionKind.List:
                case CollectionKind.Dictionary:
                    incrementCollectionCountMethod = XmlFormatGeneratorStatics.IncrementCollectionCountMethod;
                    break;

                case CollectionKind.GenericCollection:
                case CollectionKind.GenericList:
                    incrementCollectionCountMethod = XmlFormatGeneratorStatics.IncrementCollectionCountGenericMethod.MakeGenericMethod(collectionContract.ItemType);
                    break;

                case CollectionKind.GenericDictionary:
                    incrementCollectionCountMethod = XmlFormatGeneratorStatics.IncrementCollectionCountGenericMethod.MakeGenericMethod(Globals.TypeOfKeyValuePair.MakeGenericType(collectionContract.ItemType.GetGenericArguments()));
                    break;
                }
                if (incrementCollectionCountMethod != null)
                {
                    incrementCollectionCountMethod.Invoke(context, new object [] { writer, objLocal });
                }

                bool    isDictionary = false, isGenericDictionary = false;
                Type    enumeratorType = null;
                Type [] keyValueTypes  = null;
                if (collectionContract.Kind == CollectionKind.GenericDictionary)
                {
                    isGenericDictionary = true;
                    keyValueTypes       = collectionContract.ItemType.GetGenericArguments();
                    enumeratorType      = Globals.TypeOfGenericDictionaryEnumerator.MakeGenericType(keyValueTypes);
                }
                else if (collectionContract.Kind == CollectionKind.Dictionary)
                {
                    isDictionary   = true;
                    keyValueTypes  = new Type[] { Globals.TypeOfObject, Globals.TypeOfObject };
                    enumeratorType = Globals.TypeOfDictionaryEnumerator;
                }
                else
                {
                    enumeratorType = collectionContract.GetEnumeratorMethod.ReturnType;
                }
                MethodInfo moveNextMethod   = enumeratorType.GetMethod(Globals.MoveNextMethodName, BindingFlags.Instance | BindingFlags.Public, null, Globals.EmptyTypeArray, null);
                MethodInfo getCurrentMethod = enumeratorType.GetMethod(Globals.GetCurrentMethodName, BindingFlags.Instance | BindingFlags.Public, null, Globals.EmptyTypeArray, null);
                if (moveNextMethod == null || getCurrentMethod == null)
                {
                    if (enumeratorType.IsInterface)
                    {
                        if (moveNextMethod == null)
                        {
                            moveNextMethod = JsonFormatGeneratorStatics.MoveNextMethod;
                        }
                        if (getCurrentMethod == null)
                        {
                            getCurrentMethod = JsonFormatGeneratorStatics.GetCurrentMethod;
                        }
                    }
                    else
                    {
                        Type           ienumeratorInterface = Globals.TypeOfIEnumerator;
                        CollectionKind kind = collectionContract.Kind;
                        if (kind == CollectionKind.GenericDictionary || kind == CollectionKind.GenericCollection || kind == CollectionKind.GenericEnumerable)
                        {
                            Type[] interfaceTypes = enumeratorType.GetInterfaces();
                            foreach (Type interfaceType in interfaceTypes)
                            {
                                if (interfaceType.IsGenericType &&
                                    interfaceType.GetGenericTypeDefinition() == Globals.TypeOfIEnumeratorGeneric &&
                                    interfaceType.GetGenericArguments()[0] == collectionContract.ItemType)
                                {
                                    ienumeratorInterface = interfaceType;
                                    break;
                                }
                            }
                        }
                        if (moveNextMethod == null)
                        {
                            moveNextMethod = CollectionDataContract.GetTargetMethodWithName(Globals.MoveNextMethodName, enumeratorType, ienumeratorInterface);
                        }
                        if (getCurrentMethod == null)
                        {
                            getCurrentMethod = CollectionDataContract.GetTargetMethodWithName(Globals.GetCurrentMethodName, enumeratorType, ienumeratorInterface);
                        }
                    }
                }
                Type   elementType  = getCurrentMethod.ReturnType;
                object currentValue = null;                 // of elementType

                var enumerator = (IEnumerator)collectionContract.GetEnumeratorMethod.Invoke(objLocal, new object [0]);
                if (isDictionary)
                {
                    ConstructorInfo dictEnumCtor = enumeratorType.GetConstructor(Globals.ScanAllMembers, null, new Type[] { Globals.TypeOfIDictionaryEnumerator }, null);
                    enumerator = (IEnumerator)dictEnumCtor.Invoke(new object [] { enumerator });
                }
                else if (isGenericDictionary)
                {
                    Type            ctorParam    = Globals.TypeOfIEnumeratorGeneric.MakeGenericType(Globals.TypeOfKeyValuePair.MakeGenericType(keyValueTypes));
                    ConstructorInfo dictEnumCtor = enumeratorType.GetConstructor(Globals.ScanAllMembers, null, new Type[] { ctorParam }, null);
                    enumerator = (IEnumerator)Activator.CreateInstance(enumeratorType, new object [] { enumerator });
                }

                bool canWriteSimpleDictionary = isDictionary || isGenericDictionary;

                bool         writeSimpleDictionary = canWriteSimpleDictionary && context.UseSimpleDictionaryFormat;
                PropertyInfo genericDictionaryKeyProperty = null, genericDictionaryValueProperty = null;

                if (canWriteSimpleDictionary)
                {
                    Type genericDictionaryKeyValueType = Globals.TypeOfKeyValue.MakeGenericType(keyValueTypes);
                    genericDictionaryKeyProperty   = genericDictionaryKeyValueType.GetProperty(JsonGlobals.KeyString);
                    genericDictionaryValueProperty = genericDictionaryKeyValueType.GetProperty(JsonGlobals.ValueString);
                }

                if (writeSimpleDictionary)
                {
                    WriteObjectAttribute();
                    object key, value;
                    var    empty_args = new object [0];
                    while ((bool)moveNextMethod.Invoke(enumerator, empty_args))
                    {
                        currentValue = getCurrentMethod.Invoke(enumerator, empty_args);
                        key          = CodeInterpreter.GetMember(genericDictionaryKeyProperty, currentValue);
                        value        = CodeInterpreter.GetMember(genericDictionaryValueProperty, currentValue);

                        WriteStartElement(key, 0 /*nameIndex*/);
                        WriteValue(genericDictionaryValueProperty.PropertyType, value);
                        WriteEndElement();
                    }
                }
                else
                {
                    WriteArrayAttribute();

                    var emptyArray = new object [0];
                    while (enumerator != null && enumerator.MoveNext())
                    {
                        currentValue = getCurrentMethod.Invoke(enumerator, emptyArray);

                        if (incrementCollectionCountMethod == null)
                        {
                            XmlFormatGeneratorStatics.IncrementItemCountMethod.Invoke(context, new object [] { 1 });
                        }

                        if (!TryWritePrimitive(elementType, () => currentValue, null, null, itemName, 0))
                        {
                            WriteStartElement(itemName, 0);
                            if (isGenericDictionary || isDictionary)
                            {
                                var jc = JsonDataContract.GetJsonDataContract(XmlObjectSerializerWriteContextComplexJson.GetRevisedItemContract(
                                                                                  collectionDataContract.ItemContract));
                                // FIXME: this TypeHandle might be wrong; there is no easy way to get Type for currentValue though.
                                DataContractJsonSerializer.WriteJsonValue(jc, writer, currentValue, context, currentValue.GetType().TypeHandle);
                            }
                            else
                            {
                                WriteValue(elementType, currentValue);
                            }
                            WriteEndElement();
                        }
                    }
                }
            }
        }
        void WriteCollection(CollectionDataContract collectionContract)
        {
            XmlDictionaryString itemNamespace = dataContract.Namespace;

            XmlDictionaryString itemName = collectionDataContract.CollectionItemName;

            if (collectionContract.ChildElementNamespace != null)
            {
                writer.WriteNamespaceDecl(collectionDataContract.ChildElementNamespace);
            }

            if (collectionContract.Kind == CollectionKind.Array)
            {
                Type itemType = collectionContract.ItemType;
                int  i;

                // This check does not exist in the original dynamic code,
                // but there is no other way to check type mismatch.
                // CollectionSerialization.ArrayContract() shows that it is required.
                if (objLocal.GetType().GetElementType() != itemType)
                {
                    throw new InvalidCastException(string.Format("Cannot cast array of {0} to array of {1}", objLocal.GetType().GetElementType(), itemType));
                }

                ctx.IncrementArrayCount(writer, (Array)objLocal);

                if (!TryWritePrimitiveArray(collectionContract.UnderlyingType, itemType, () => objLocal, itemName, itemNamespace))
                {
                    var arr = (Array)objLocal;
                    var idx = new int [1];
                    for (i = 0; i < arr.Length; i++)
                    {
                        if (!TryWritePrimitive(itemType, null, null, i, itemNamespace, itemName, 0))
                        {
                            WriteStartElement(itemType, collectionContract.Namespace, itemNamespace, itemName, 0);
                            idx [0] = i;
                            var mbrVal = arr.GetValue(idx);
                            WriteValue(itemType, mbrVal, false);
                            WriteEndElement();
                        }
                    }
                }
            }
            else
            {
                // This check does not exist in the original dynamic code,
                // but there is no other way to check type mismatch.
                // CollectionSerialization.ArrayContract() shows that it is required.
                if (!collectionContract.UnderlyingType.IsAssignableFrom(objLocal.GetType()))
                {
                    throw new InvalidCastException(string.Format("Cannot cast {0} to {1}", objLocal.GetType(), collectionContract.UnderlyingType));
                }

                MethodInfo incrementCollectionCountMethod = null;
                switch (collectionContract.Kind)
                {
                case CollectionKind.Collection:
                case CollectionKind.List:
                case CollectionKind.Dictionary:
                    incrementCollectionCountMethod = XmlFormatGeneratorStatics.IncrementCollectionCountMethod;
                    break;

                case CollectionKind.GenericCollection:
                case CollectionKind.GenericList:
                    incrementCollectionCountMethod = XmlFormatGeneratorStatics.IncrementCollectionCountGenericMethod.MakeGenericMethod(collectionContract.ItemType);
                    break;

                case CollectionKind.GenericDictionary:
                    incrementCollectionCountMethod = XmlFormatGeneratorStatics.IncrementCollectionCountGenericMethod.MakeGenericMethod(Globals.TypeOfKeyValuePair.MakeGenericType(collectionContract.ItemType.GetGenericArguments()));
                    break;
                }
                if (incrementCollectionCountMethod != null)
                {
                    incrementCollectionCountMethod.Invoke(ctx, new object [] { writer, objLocal });
                }

                bool    isDictionary = false, isGenericDictionary = false;
                Type    enumeratorType = null;
                Type [] keyValueTypes  = null;
                if (collectionContract.Kind == CollectionKind.GenericDictionary)
                {
                    isGenericDictionary = true;
                    keyValueTypes       = collectionContract.ItemType.GetGenericArguments();
                    enumeratorType      = Globals.TypeOfGenericDictionaryEnumerator.MakeGenericType(keyValueTypes);
                }
                else if (collectionContract.Kind == CollectionKind.Dictionary)
                {
                    isDictionary   = true;
                    keyValueTypes  = new Type[] { Globals.TypeOfObject, Globals.TypeOfObject };
                    enumeratorType = Globals.TypeOfDictionaryEnumerator;
                }
                else
                {
                    enumeratorType = collectionContract.GetEnumeratorMethod.ReturnType;
                }
                MethodInfo moveNextMethod   = enumeratorType.GetMethod(Globals.MoveNextMethodName, BindingFlags.Instance | BindingFlags.Public, null, Globals.EmptyTypeArray, null);
                MethodInfo getCurrentMethod = enumeratorType.GetMethod(Globals.GetCurrentMethodName, BindingFlags.Instance | BindingFlags.Public, null, Globals.EmptyTypeArray, null);
                if (moveNextMethod == null || getCurrentMethod == null)
                {
                    if (enumeratorType.IsInterface)
                    {
                        if (moveNextMethod == null)
                        {
                            moveNextMethod = XmlFormatGeneratorStatics.MoveNextMethod;
                        }
                        if (getCurrentMethod == null)
                        {
                            getCurrentMethod = XmlFormatGeneratorStatics.GetCurrentMethod;
                        }
                    }
                    else
                    {
                        Type           ienumeratorInterface = Globals.TypeOfIEnumerator;
                        CollectionKind kind = collectionContract.Kind;
                        if (kind == CollectionKind.GenericDictionary || kind == CollectionKind.GenericCollection || kind == CollectionKind.GenericEnumerable)
                        {
                            Type[] interfaceTypes = enumeratorType.GetInterfaces();
                            foreach (Type interfaceType in interfaceTypes)
                            {
                                if (interfaceType.IsGenericType &&
                                    interfaceType.GetGenericTypeDefinition() == Globals.TypeOfIEnumeratorGeneric &&
                                    interfaceType.GetGenericArguments()[0] == collectionContract.ItemType)
                                {
                                    ienumeratorInterface = interfaceType;
                                    break;
                                }
                            }
                        }
                        if (moveNextMethod == null)
                        {
                            moveNextMethod = CollectionDataContract.GetTargetMethodWithName(Globals.MoveNextMethodName, enumeratorType, ienumeratorInterface);
                        }
                        if (getCurrentMethod == null)
                        {
                            getCurrentMethod = CollectionDataContract.GetTargetMethodWithName(Globals.GetCurrentMethodName, enumeratorType, ienumeratorInterface);
                        }
                    }
                }
                Type   elementType  = getCurrentMethod.ReturnType;
                object currentValue = null;                 // of elementType

                var enumerator = (IEnumerator)collectionContract.GetEnumeratorMethod.Invoke(objLocal, new object [0]);
                if (isDictionary)
                {
                    enumerator = new CollectionDataContract.DictionaryEnumerator((IDictionaryEnumerator)enumerator);
                }
                else if (isGenericDictionary)
                {
                    Type            ctorParam    = Globals.TypeOfIEnumeratorGeneric.MakeGenericType(Globals.TypeOfKeyValuePair.MakeGenericType(keyValueTypes));
                    ConstructorInfo dictEnumCtor = enumeratorType.GetConstructor(Globals.ScanAllMembers, null, new Type[] { ctorParam }, null);
                    enumerator = (IEnumerator)Activator.CreateInstance(enumeratorType, new object [] { enumerator });
                }

                var emptyArray = new object [0];
                while (enumerator != null && enumerator.MoveNext())
                {
                    currentValue = getCurrentMethod.Invoke(enumerator, emptyArray);

                    if (incrementCollectionCountMethod == null)
                    {
                        XmlFormatGeneratorStatics.IncrementItemCountMethod.Invoke(ctx, new object [] { 1 });
                    }

                    if (!TryWritePrimitive(elementType, () => currentValue, null, null, itemNamespace, itemName, 0))
                    {
                        WriteStartElement(elementType, collectionContract.Namespace, itemNamespace, itemName, 0);
                        if (isGenericDictionary || isDictionary)
                        {
                            collectionDataContract.ItemContract.WriteXmlValue(writer, currentValue, ctx);
                        }
                        else
                        {
                            WriteValue(elementType, currentValue, false);
                        }
                        WriteEndElement();
                    }
                }
            }
        }
            private void WriteCollection(CollectionDataContract collectionContract)
            {
                LocalBuilder var = this.ilg.DeclareLocal(typeof(XmlDictionaryString), "itemName");

                this.ilg.Load(this.contextArg);
                this.ilg.LoadMember(JsonFormatGeneratorStatics.CollectionItemNameProperty);
                this.ilg.Store(var);
                if (collectionContract.Kind == CollectionKind.Array)
                {
                    Type         itemType = collectionContract.ItemType;
                    LocalBuilder local    = this.ilg.DeclareLocal(Globals.TypeOfInt, "i");
                    this.ilg.Call(this.contextArg, XmlFormatGeneratorStatics.IncrementArrayCountMethod, this.xmlWriterArg, this.objectLocal);
                    if (!this.TryWritePrimitiveArray(collectionContract.UnderlyingType, itemType, this.objectLocal, var))
                    {
                        this.WriteArrayAttribute();
                        this.ilg.For(local, 0, this.objectLocal);
                        if (!this.TryWritePrimitive(itemType, null, null, local, var, 0))
                        {
                            this.WriteStartElement(var, 0);
                            this.ilg.LoadArrayElement(this.objectLocal, local);
                            LocalBuilder builder3 = this.ilg.DeclareLocal(itemType, "memberValue");
                            this.ilg.Stloc(builder3);
                            this.WriteValue(builder3);
                            this.WriteEndElement();
                        }
                        this.ilg.EndFor();
                    }
                }
                else
                {
                    MethodInfo methodInfo = null;
                    switch (collectionContract.Kind)
                    {
                    case CollectionKind.GenericDictionary:
                        methodInfo = XmlFormatGeneratorStatics.IncrementCollectionCountGenericMethod.MakeGenericMethod(new Type[] { Globals.TypeOfKeyValuePair.MakeGenericType(collectionContract.ItemType.GetGenericArguments()) });
                        break;

                    case CollectionKind.Dictionary:
                    case CollectionKind.List:
                    case CollectionKind.Collection:
                        methodInfo = XmlFormatGeneratorStatics.IncrementCollectionCountMethod;
                        break;

                    case CollectionKind.GenericList:
                    case CollectionKind.GenericCollection:
                        methodInfo = XmlFormatGeneratorStatics.IncrementCollectionCountGenericMethod.MakeGenericMethod(new Type[] { collectionContract.ItemType });
                        break;
                    }
                    if (methodInfo != null)
                    {
                        this.ilg.Call(this.contextArg, methodInfo, this.xmlWriterArg, this.objectLocal);
                    }
                    bool   flag          = false;
                    bool   flag2         = false;
                    Type   type          = null;
                    Type[] typeArguments = null;
                    if (collectionContract.Kind == CollectionKind.GenericDictionary)
                    {
                        flag2         = true;
                        typeArguments = collectionContract.ItemType.GetGenericArguments();
                        type          = Globals.TypeOfGenericDictionaryEnumerator.MakeGenericType(typeArguments);
                    }
                    else if (collectionContract.Kind == CollectionKind.Dictionary)
                    {
                        flag          = true;
                        typeArguments = new Type[] { Globals.TypeOfObject, Globals.TypeOfObject };
                        type          = Globals.TypeOfDictionaryEnumerator;
                    }
                    else
                    {
                        type = collectionContract.GetEnumeratorMethod.ReturnType;
                    }
                    MethodInfo moveNextMethod   = type.GetMethod("MoveNext", BindingFlags.Public | BindingFlags.Instance, null, Globals.EmptyTypeArray, null);
                    MethodInfo getCurrentMethod = type.GetMethod("get_Current", BindingFlags.Public | BindingFlags.Instance, null, Globals.EmptyTypeArray, null);
                    if ((moveNextMethod == null) || (getCurrentMethod == null))
                    {
                        if (type.IsInterface)
                        {
                            if (moveNextMethod == null)
                            {
                                moveNextMethod = JsonFormatGeneratorStatics.MoveNextMethod;
                            }
                            if (getCurrentMethod == null)
                            {
                                getCurrentMethod = JsonFormatGeneratorStatics.GetCurrentMethod;
                            }
                        }
                        else
                        {
                            Type typeOfIEnumerator = Globals.TypeOfIEnumerator;
                            switch (collectionContract.Kind)
                            {
                            case CollectionKind.GenericDictionary:
                            case CollectionKind.GenericCollection:
                            case CollectionKind.GenericEnumerable:
                                foreach (Type type4 in type.GetInterfaces())
                                {
                                    if ((type4.IsGenericType && (type4.GetGenericTypeDefinition() == Globals.TypeOfIEnumeratorGeneric)) && (type4.GetGenericArguments()[0] == collectionContract.ItemType))
                                    {
                                        typeOfIEnumerator = type4;
                                        break;
                                    }
                                }
                                break;
                            }
                            if (moveNextMethod == null)
                            {
                                moveNextMethod = CollectionDataContract.GetTargetMethodWithName("MoveNext", type, typeOfIEnumerator);
                            }
                            if (getCurrentMethod == null)
                            {
                                getCurrentMethod = CollectionDataContract.GetTargetMethodWithName("get_Current", type, typeOfIEnumerator);
                            }
                        }
                    }
                    Type         returnType = getCurrentMethod.ReturnType;
                    LocalBuilder builder4   = this.ilg.DeclareLocal(returnType, "currentValue");
                    LocalBuilder builder5   = this.ilg.DeclareLocal(type, "enumerator");
                    this.ilg.Call(this.objectLocal, collectionContract.GetEnumeratorMethod);
                    if (flag)
                    {
                        ConstructorInfo constructorInfo = type.GetConstructor(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance, null, new Type[] { Globals.TypeOfIDictionaryEnumerator }, null);
                        this.ilg.ConvertValue(collectionContract.GetEnumeratorMethod.ReturnType, Globals.TypeOfIDictionaryEnumerator);
                        this.ilg.New(constructorInfo);
                    }
                    else if (flag2)
                    {
                        Type            target = Globals.TypeOfIEnumeratorGeneric.MakeGenericType(new Type[] { Globals.TypeOfKeyValuePair.MakeGenericType(typeArguments) });
                        ConstructorInfo info5  = type.GetConstructor(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance, null, new Type[] { target }, null);
                        this.ilg.ConvertValue(collectionContract.GetEnumeratorMethod.ReturnType, target);
                        this.ilg.New(info5);
                    }
                    this.ilg.Stloc(builder5);
                    this.WriteArrayAttribute();
                    this.ilg.ForEach(builder4, returnType, type, builder5, getCurrentMethod);
                    if (methodInfo == null)
                    {
                        this.ilg.Call(this.contextArg, XmlFormatGeneratorStatics.IncrementItemCountMethod, 1);
                    }
                    if (!this.TryWritePrimitive(returnType, builder4, null, null, var, 0))
                    {
                        this.WriteStartElement(var, 0);
                        if (flag2 || flag)
                        {
                            this.ilg.Call(this.dataContractArg, JsonFormatGeneratorStatics.GetItemContractMethod);
                            this.ilg.Call(JsonFormatGeneratorStatics.GetRevisedItemContractMethod);
                            this.ilg.Call(JsonFormatGeneratorStatics.GetJsonDataContractMethod);
                            this.ilg.Load(this.xmlWriterArg);
                            this.ilg.Load(builder4);
                            this.ilg.ConvertValue(builder4.LocalType, Globals.TypeOfObject);
                            this.ilg.Load(this.contextArg);
                            this.ilg.Load(builder4.LocalType);
                            this.ilg.LoadMember(JsonFormatGeneratorStatics.TypeHandleProperty);
                            this.ilg.Call(JsonFormatGeneratorStatics.WriteJsonValueMethod);
                        }
                        else
                        {
                            this.WriteValue(builder4);
                        }
                        this.WriteEndElement();
                    }
                    this.ilg.EndForEach(moveNextMethod);
                }
            }