protected override object ReflectionReadDictionaryItem(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context, CollectionDataContract collectionContract) { var jsonContext = context as XmlObjectSerializerReadContextComplexJson; Debug.Assert(jsonContext != null); Debug.Assert(collectionContract.Kind == CollectionKind.Dictionary || collectionContract.Kind == CollectionKind.GenericDictionary); context.ReadAttributes(xmlReader); var itemContract = XmlObjectSerializerWriteContextComplexJson.GetRevisedItemContract(collectionContract.ItemContract); return(DataContractJsonSerializer.ReadJsonValue(itemContract, xmlReader, jsonContext)); }
object ReadCollectionItem(CollectionDataContract collectionContract, Type itemType) { if (collectionContract.Kind == CollectionKind.Dictionary || collectionContract.Kind == CollectionKind.GenericDictionary) { context.ResetAttributes(); var revisedContract = XmlObjectSerializerWriteContextComplexJson.GetRevisedItemContract(collectionContract.ItemContract); var v = DataContractJsonSerializer.ReadJsonValue(revisedContract, xmlReader, context); return(CodeInterpreter.ConvertValue(v, Globals.TypeOfObject, itemType)); } else { return(ReadValue(itemType, JsonGlobals.itemString)); } }
public void ReflectionWriteCollection(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContextComplexJson context, CollectionDataContract collectionContract) { JsonWriterDelegator jsonWriter = xmlWriter as JsonWriterDelegator; if (jsonWriter == null) { throw new ArgumentException(nameof(xmlWriter)); } XmlDictionaryString itemName = context.CollectionItemName; if (collectionContract.Kind == CollectionKind.Array) { context.IncrementArrayCount(jsonWriter, (Array)obj); Type itemType = collectionContract.ItemType; if (!ReflectionTryWritePrimitiveArray(jsonWriter, obj, collectionContract.UnderlyingType, itemType, itemName)) { ReflectionWriteArrayAttribute(jsonWriter); Array array = (Array)obj; PrimitiveDataContract primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract(itemType); for (int i = 0; i < array.Length; ++i) { _reflectionClassWriter.ReflectionWriteStartElement(jsonWriter, itemName); _reflectionClassWriter.ReflectionWriteValue(jsonWriter, context, itemType, array.GetValue(i), false, primitiveContract); _reflectionClassWriter.ReflectionWriteEndElement(jsonWriter); } } } else { collectionContract.IncrementCollectionCount(jsonWriter, obj, context); IEnumerator enumerator = collectionContract.GetEnumeratorForCollection(obj); bool canWriteSimpleDictionary = collectionContract.Kind == CollectionKind.GenericDictionary || collectionContract.Kind == CollectionKind.Dictionary; bool useSimpleDictionaryFormat = context.UseSimpleDictionaryFormat; if (canWriteSimpleDictionary && useSimpleDictionaryFormat) { ReflectionWriteObjectAttribute(jsonWriter); Type[] itemTypeGenericArguments = collectionContract.ItemType.GetGenericArguments(); Type dictionaryValueType = itemTypeGenericArguments.Length == 2 ? itemTypeGenericArguments[1] : null; while (enumerator.MoveNext()) { object current = enumerator.Current; object key = ((IKeyValue)current).Key; object value = ((IKeyValue)current).Value; _reflectionClassWriter.ReflectionWriteStartElement(jsonWriter, key.ToString()); _reflectionClassWriter.ReflectionWriteValue(jsonWriter, context, dictionaryValueType ?? value.GetType(), value, false, primitiveContractForParamType: null); _reflectionClassWriter.ReflectionWriteEndElement(jsonWriter); } } else { ReflectionWriteArrayAttribute(jsonWriter); PrimitiveDataContract primitiveContractForType = PrimitiveDataContract.GetPrimitiveDataContract(collectionContract.UnderlyingType); if (primitiveContractForType != null && primitiveContractForType.UnderlyingType != Globals.TypeOfObject) { while (enumerator.MoveNext()) { object current = enumerator.Current; context.IncrementItemCount(1); primitiveContractForType.WriteXmlElement(jsonWriter, current, context, itemName, null /*namespace*/); } } else { Type elementType = collectionContract.GetCollectionElementType(); bool isDictionary = collectionContract.Kind == CollectionKind.Dictionary || collectionContract.Kind == CollectionKind.GenericDictionary; DataContract itemContract = null; JsonDataContract jsonDataContract = null; if (isDictionary) { itemContract = XmlObjectSerializerWriteContextComplexJson.GetRevisedItemContract(collectionContract.ItemContract); jsonDataContract = JsonDataContract.GetJsonDataContract(itemContract); } while (enumerator.MoveNext()) { object current = enumerator.Current; context.IncrementItemCount(1); _reflectionClassWriter.ReflectionWriteStartElement(jsonWriter, itemName); if (isDictionary) { jsonDataContract.WriteJsonValue(jsonWriter, current, context, collectionContract.ItemType.TypeHandle); } else { _reflectionClassWriter.ReflectionWriteValue(jsonWriter, context, elementType, current, false, primitiveContractForParamType: null); } _reflectionClassWriter.ReflectionWriteEndElement(jsonWriter); } } } } }
//Deserialize '[...]' json string. The contents of the list can also be a dictionary i.e. [{...}]. The content type is detected //based on the type of CollectionDataContract.ItemContract. public static object ConvertICollectionToCollectionDataContract(DataContractJsonSerializer serializer, CollectionDataContract contract, object deserializedValue, XmlObjectSerializerReadContextComplexJson context) { Dictionary <string, object> valueAsDictionary = deserializedValue as Dictionary <string, object>; //Check to see if the dictionary (if it is a dictionary)is a regular Dictionary i.e { Key="key"; Value="value} and doesnt contain the __type string //for ex. the dictionary { __type="XXX"; Key="key"; Value="value} needs to be parsed as ClassDataContract if (valueAsDictionary != null && (!valueAsDictionary.ContainsKey(JsonGlobals.KeyString) || valueAsDictionary.ContainsKey(JsonGlobals.ServerTypeString))) { //If not then its a dictionary for either of these cases //1. Empty object - {} //2. Containes the __type information //3. Is a DateTimeOffsetDictionary return(ConvertDictionary(serializer, contract, valueAsDictionary, context)); } object returnValue = (contract.Constructor != null) ? contract.Constructor.Invoke(Globals.EmptyTypeArray) : null; bool isCollectionDataContractDictionary = contract.IsDictionary; MethodInfo addMethod = contract.AddMethod; bool convertToArray = contract.Kind == CollectionKind.Array; if (contract.UnderlyingType.GetTypeInfo().IsInterface || returnValue == null) { switch (contract.Kind) { case CollectionKind.Collection: case CollectionKind.GenericCollection: case CollectionKind.Enumerable: case CollectionKind.GenericEnumerable: case CollectionKind.List: case CollectionKind.GenericList: case CollectionKind.Array: if (contract.UnderlyingType.GetTypeInfo().IsValueType) { //Initialize struct returnValue = XmlFormatReaderGenerator.TryGetUninitializedObjectWithFormatterServices(contract.UnderlyingType); } else { returnValue = Activator.CreateInstance(Globals.TypeOfListGeneric.MakeGenericType(contract.ItemType)); convertToArray = true; } break; case CollectionKind.GenericDictionary: returnValue = Activator.CreateInstance(Globals.TypeOfDictionaryGeneric.MakeGenericType(contract.ItemType.GetGenericArguments())); break; case CollectionKind.Dictionary: returnValue = Activator.CreateInstance(Globals.TypeOfDictionaryGeneric.MakeGenericType(Globals.TypeOfObject, Globals.TypeOfObject)); break; } } if (addMethod == null) { //addMethod is null for IDictionary, IList and array types. Type[] paramArray = (contract.ItemType.GetTypeInfo().IsGenericType&& !convertToArray) ? contract.ItemType.GetGenericArguments() : new Type[] { contract.ItemType }; addMethod = returnValue.GetType().GetMethod(Globals.AddMethodName, paramArray); } IEnumerator enumerator = ((ICollection)deserializedValue).GetEnumerator(); object currentItem = null; object[] currentItemArray = null; while (enumerator.MoveNext()) { DataContract itemContract = contract.ItemContract; if (itemContract is ClassDataContract) { itemContract = XmlObjectSerializerWriteContextComplexJson.GetRevisedItemContract(itemContract); } currentItem = serializer.ConvertObjectToDataContract(itemContract, enumerator.Current, context); currentItemArray = new object[] { currentItem }; if (isCollectionDataContractDictionary) { Type currentItemType = currentItem.GetType(); MemberInfo keyMember = currentItemType.GetMember("Key")[0]; MemberInfo valueMember = currentItemType.GetMember("Value")[0]; currentItemArray = new object[] { DataContractToObjectConverter.GetMemberValue(currentItem, keyMember, currentItemType), DataContractToObjectConverter.GetMemberValue(currentItem, valueMember, currentItemType) }; } addMethod.Invoke(returnValue, currentItemArray); } return((convertToArray) ? ConvertToArray(contract.ItemType, (ICollection)returnValue) : returnValue); }
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(); } } } } }