private 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, Array.Empty <Type>());
MethodInfo getCurrentMethod = enumeratorType.GetMethod(Globals.GetCurrentMethodName, BindingFlags.Instance | BindingFlags.Public, Array.Empty <Type>());
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, new Type[] { ctorParam });
_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);
}
}