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