public void ReflectionWriteCollection(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext context, CollectionDataContract collectionDataContract) { XmlDictionaryString ns = collectionDataContract.Namespace; XmlDictionaryString itemName = collectionDataContract.CollectionItemName; if (collectionDataContract.ChildElementNamespace != null) { xmlWriter.WriteNamespaceDecl(collectionDataContract.ChildElementNamespace); } if (collectionDataContract.Kind == CollectionKind.Array) { context.IncrementArrayCount(xmlWriter, (Array)obj); Type itemType = collectionDataContract.ItemType; if (!ReflectionTryWritePrimitiveArray(xmlWriter, obj, collectionDataContract.UnderlyingType, itemType, itemName, ns)) { Array array = (Array)obj; PrimitiveDataContract primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract(itemType); for (int i = 0; i < array.Length; ++i) { _reflectionClassWriter.ReflectionWriteStartElement(xmlWriter, itemType, ns, ns.Value, itemName.Value, 0); _reflectionClassWriter.ReflectionWriteValue(xmlWriter, context, itemType, array.GetValue(i), false, primitiveContract); _reflectionClassWriter.ReflectionWriteEndElement(xmlWriter); } } } else { collectionDataContract.IncrementCollectionCount(xmlWriter, obj, context); IEnumerator enumerator = collectionDataContract.GetEnumeratorForCollection(obj); PrimitiveDataContract primitiveContractForType = PrimitiveDataContract.GetPrimitiveDataContract(collectionDataContract.UnderlyingType); if (primitiveContractForType != null && primitiveContractForType.UnderlyingType != Globals.TypeOfObject) { while (enumerator.MoveNext()) { object current = enumerator.Current; context.IncrementItemCount(1); primitiveContractForType.WriteXmlElement(xmlWriter, current, context, itemName, ns); } } else { Type elementType = collectionDataContract.GetCollectionElementType(); bool isDictionary = collectionDataContract.Kind == CollectionKind.Dictionary || collectionDataContract.Kind == CollectionKind.GenericDictionary; while (enumerator.MoveNext()) { object current = enumerator.Current; context.IncrementItemCount(1); _reflectionClassWriter.ReflectionWriteStartElement(xmlWriter, elementType, ns, ns.Value, itemName.Value, 0); if (isDictionary) { collectionDataContract.ItemContract.WriteXmlValue(xmlWriter, current, context); } else { _reflectionClassWriter.ReflectionWriteValue(xmlWriter, context, elementType, current, false, primitiveContractForParamType: null); } _reflectionClassWriter.ReflectionWriteEndElement(xmlWriter); } } } }
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(); } } } }