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(); } } }
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); } }